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