28 #include <SimoxUtility/algorithm/string/string_tools.h>
29 #include <VirtualRobot/CollisionDetection/CollisionChecker.h>
30 #include <VirtualRobot/Obstacle.h>
31 #include <VirtualRobot/RobotNodeSet.h>
44 #define FLOOR_OBJ_STR "FLOOR"
49 SelfCollisionChecker::_preOnInitRobotUnit()
53 selfCollisionAvoidanceRobot = _module<RobotData>().cloneRobot(
true);
56 const std::string colModelsString =
57 getProperty<std::string>(
"SelfCollisionCheck_ModelGroupsToCheck").getValue();
58 std::vector<std::string> groups;
59 if (!colModelsString.empty())
63 ARMARX_DEBUG <<
"Processing groups for self collision checking:";
64 for (std::string& group : groups)
68 simox::alg::trim_if(group,
" \t{}");
69 std::set<std::set<std::string>> setsOfNode;
72 if (splittedRaw.size() < 2)
76 for (
auto& subentry : splittedRaw)
78 simox::alg::trim_if(subentry,
" \t{}");
79 if (selfCollisionAvoidanceRobot->hasRobotNodeSet(subentry))
81 std::set<std::string> nodes;
83 for (
const auto& node :
84 selfCollisionAvoidanceRobot->getRobotNodeSet(subentry)
87 if (!node->getCollisionModel())
92 << node->getName() <<
"'";
95 nodes.emplace(node->getName());
97 <<
", node: " << node->getName();
99 setsOfNode.emplace(std::move(nodes));
101 else if (selfCollisionAvoidanceRobot->hasRobotNode(subentry))
104 if (!selfCollisionAvoidanceRobot->getRobotNode(subentry)
105 ->getCollisionModel())
109 <<
"Self Collision Avoidance: No collision model found for '"
110 << selfCollisionAvoidanceRobot->getRobotNode(subentry)
115 setsOfNode.emplace(std::set<std::string>{subentry});
121 setsOfNode.emplace(std::set<std::string>{subentry});
126 ARMARX_ERROR <<
"No RobotNodeSet or RobotNode with name '" << subentry
128 << _module<RobotData>().getRobotFileName()
135 auto addCombinationOfSetsToCollisionCheck =
136 [
this](
const std::set<std::string>&
a,
const std::set<std::string>& b)
138 for (
const auto& nodeA :
a)
140 for (
const auto& nodeB : b)
148 ARMARX_DEBUG <<
"------------ " << nodeA <<
" " << nodeB;
149 namePairsToCheck.emplace(nodeA, nodeB);
153 ARMARX_DEBUG <<
"------------ " << nodeB <<
" " << nodeA;
154 namePairsToCheck.emplace(nodeB, nodeA);
161 for (
auto setAIt = setsOfNode.begin(); setAIt != setsOfNode.end(); ++setAIt)
163 auto setBIt = setAIt;
165 for (; setBIt != setsOfNode.end(); ++setBIt)
167 addCombinationOfSetsToCollisionCheck(*setAIt, *setBIt);
172 ARMARX_DEBUG <<
"-------- group: " << group <<
"...DONE!\n";
174 ARMARX_DEBUG <<
"Processing groups for self collision checking...DONE!";
177 getProperty<float>(
"SelfCollisionCheck_Frequency").getValue());
179 getProperty<float>(
"SelfCollisionCheck_MinSelfDistance").getValue());
187 std::lock_guard<std::mutex> guard{selfCollisionDataMutex};
190 throw InvalidArgumentException{std::string{__FILE__} +
": " + BOOST_CURRENT_FUNCTION +
193 if (
distance == minSelfDistance && !nodePairsToCheck.empty())
200 selfCollisionAvoidanceRobot = _module<RobotData>().cloneRobot(
true);
201 selfCollisionAvoidanceRobotNodes = selfCollisionAvoidanceRobot->getRobotNodes();
202 nodePairsToCheck.clear();
205 floor.reset(
new VirtualRobot::SceneObjectSet(
206 "FLOORSET", selfCollisionAvoidanceRobot->getCollisionChecker()));
207 static constexpr
float floorSize = 1e16f;
208 VirtualRobot::ObstaclePtr boxOb = VirtualRobot::Obstacle::createBox(
211 std::min(0.001f, minSelfDistance / 2),
212 VirtualRobot::VisualizationFactory::Color::Red(),
214 selfCollisionAvoidanceRobot->getCollisionChecker());
217 floor->addSceneObject(boxOb);
220 for (
const auto& node : selfCollisionAvoidanceRobotNodes)
222 if (node->getCollisionModel())
224 node->getCollisionModel()->inflateModel(minSelfDistance / 2.f);
232 std::vector<std::pair<std::string, std::string>> validNamePairsToCheck(namePairsToCheck.begin(), namePairsToCheck.end());
234 const auto isCollisionIgnored = [
this](
const std::string&
a,
const std::string& b) ->
bool {
241 const auto nodeA = selfCollisionAvoidanceRobot->getRobotNode(
a);
242 const auto nodeB = selfCollisionAvoidanceRobot->getRobotNode(b);
244 if(nodeA ==
nullptr or nodeB ==
nullptr)
249 const std::vector<std::string> nodesIgnoredByA = nodeA->getIgnoredCollisionModels();
250 const std::vector<std::string> nodesIgnoredByB = nodeB->getIgnoredCollisionModels();
252 if(std::find(nodesIgnoredByA.begin(), nodesIgnoredByA.end(), b) != nodesIgnoredByA.end())
254 ARMARX_VERBOSE <<
"Ignoring collision between nodes: " <<
a <<
" -- " << b;
258 if(std::find(nodesIgnoredByB.begin(), nodesIgnoredByB.end(),
a) != nodesIgnoredByB.end())
260 ARMARX_VERBOSE <<
"Ignoring collision between nodes: " << b <<
" -- " <<
a;
268 validNamePairsToCheck.erase(std::remove_if(validNamePairsToCheck.begin(), validNamePairsToCheck.end(), [&isCollisionIgnored](
const auto& p) ->
bool {
269 const auto& [a, b] = p;
270 return isCollisionIgnored(a, b);
271 }), validNamePairsToCheck.end());
273 ARMARX_VERBOSE <<
"Removed " << (namePairsToCheck.size() - validNamePairsToCheck.size()) <<
" collision pairs.";
276 namePairsToCheck =
std::set(validNamePairsToCheck.begin(), validNamePairsToCheck.end());
280 for (
const auto& pair : namePairsToCheck)
284 ? floor->getSceneObject(0)
285 : selfCollisionAvoidanceRobot->getRobotNode(pair.first);
291 ? floor->getSceneObject(0)
292 : selfCollisionAvoidanceRobot->getRobotNode(pair.second);
296 nodePairsToCheck.emplace_back(first, second);
307 throw InvalidArgumentException{std::string{__FILE__} +
": " + BOOST_CURRENT_FUNCTION +
310 checkFrequency = freq;
317 return checkFrequency != 0;
324 return checkFrequency;
331 return minSelfDistance;
335 SelfCollisionChecker::_componentPropertiesUpdated(
const std::set<std::string>& changed)
338 if (changed.count(
"SelfCollisionCheck_Frequency"))
341 getProperty<float>(
"SelfCollisionCheck_Frequency").getValue());
343 if (changed.count(
"SelfCollisionCheck_MinSelfDistance"))
346 getProperty<float>(
"SelfCollisionCheck_MinSelfDistance").getValue());
351 SelfCollisionChecker::_postFinishControlThreadInitialization()
353 selfCollisionAvoidanceThread = std::thread{[&] { selfCollisionAvoidanceTask(); }};
357 SelfCollisionChecker::selfCollisionAvoidanceTask()
360 ARMARX_INFO <<
"Self collision checker: entered selfCollisionAvoidanceTask";
363 ARMARX_INFO <<
"Self collision checker: leaving selfCollisionAvoidanceTask";
367 const auto freq = checkFrequency.load();
376 const bool inEmergencyStop =
377 _module<ControlThread>().getEmergencyStopState() == eEmergencyStopActive;
378 if (inEmergencyStop || freq == 0)
383 std::this_thread::sleep_for(std::chrono::microseconds{1
'000});
386 //update robot + check
388 std::lock_guard<std::mutex> guard{selfCollisionDataMutex};
390 _module<ControlThreadDataBuffer>().updateVirtualRobot(
391 selfCollisionAvoidanceRobot, selfCollisionAvoidanceRobotNodes);
393 //check for all nodes 0
395 bool allJoints0 = true;
396 for (const auto& node : selfCollisionAvoidanceRobotNodes)
398 ARMARX_CHECK_NOT_NULL(node);
399 if (0 != node->getJointValue())
411 bool collision = false;
412 for (std::size_t idx = 0; idx < nodePairsToCheck.size(); ++idx)
414 const auto& pair = nodePairsToCheck.at(idx);
416 ARMARX_CHECK_NOT_NULL(pair.first);
417 ARMARX_CHECK_NOT_NULL(pair.second);
419 if (selfCollisionAvoidanceRobot->getCollisionChecker()->checkCollision(
420 pair.first, pair.second))
423 lastCollisionPairIndex = idx;
424 ARMARX_WARNING << "Self collision checker: COLLISION: '"
425 << pair.first->getName() << "' and '"
426 << pair.second->getName() << "'";
427 _module<Units>().getEmergencyStopMaster()->setEmergencyStopState(
428 EmergencyStopState::eEmergencyStopActive);
429 // since at least one of the NJoint-Controllers is going to cause a collision, we just kick them all.
430 _module<ControlThreadDataBuffer>().setActivateControllersRequest({});
436 ARMARX_VERBOSE << deactivateSpam()
437 << "Self collision checker: no collision found between the "
438 << nodePairsToCheck.size() << " pairs";
443 const auto duration = metronome.waitForNextTick();
445 if(not duration.isPositive())
447 ARMARX_WARNING << deactivateSpam(10) <<
448 "Self collision checking took too long. "
449 "Exceeding time budget by " << duration.toMilliSecondsDouble() << "ms.";
455 SelfCollisionChecker::_preFinishRunning()
457 throwIfInControlThread(BOOST_CURRENT_FUNCTION);
458 ARMARX_INFO << "Stopping Self Collision Avoidance.";
459 if (selfCollisionAvoidanceThread.joinable())
461 selfCollisionAvoidanceThread.join();
464 } // namespace armarx::RobotUnitModule