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()
60 const std::string colModelsString =
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
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!";
191 std::lock_guard<std::mutex> guard{selfCollisionDataMutex};
194 throw InvalidArgumentException{std::string{__FILE__} +
": " + BOOST_CURRENT_FUNCTION +
195 ": illegal distance:" + std::to_string(
distance)};
197 if (
distance == minSelfDistance && !nodePairsToCheck.empty())
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());
219 boxOb->setGlobalPose(Eigen::Matrix4f::Identity());
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)
294 VirtualRobot::SceneObjectPtr first =
296 ? floor->getSceneObject(0)
297 : selfCollisionAvoidanceRobot->getRobotNode(pair.first);
301 VirtualRobot::SceneObjectPtr second =
303 ? floor->getSceneObject(0)
304 : selfCollisionAvoidanceRobot->getRobotNode(pair.second);
308 nodePairsToCheck.emplace_back(first, second);
319 throw InvalidArgumentException{std::string{__FILE__} +
": " + BOOST_CURRENT_FUNCTION +
320 ": illegal frequency:" + std::to_string(freq)};
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"))
355 if (changed.count(
"SelfCollisionCheck_MinSelfDistance"))
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 =
390 if (inEmergencyStop || freq == 0)
395 std::this_thread::sleep_for(std::chrono::microseconds{1'000});
400 std::lock_guard<std::mutex> guard{selfCollisionDataMutex};
403 selfCollisionAvoidanceRobot, selfCollisionAvoidanceRobotNodes);
407 bool allJoints0 =
true;
408 for (
const auto& node : selfCollisionAvoidanceRobotNodes)
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);
431 if (selfCollisionAvoidanceRobot->getCollisionChecker()->checkCollision(
432 pair.first, pair.second))
435 lastCollisionPairIndex = idx;
437 << pair.first->getName() <<
"' and '"
438 << pair.second->getName() <<
"'";
440 EmergencyStopState::eEmergencyStopActive);
449 <<
"Self collision checker: no collision found between the "
450 << nodePairsToCheck.size() <<
" pairs";
455 const auto duration = metronome.waitForNextTick();
457 if (not duration.isPositive())
460 <<
"Self collision checking took too long. "
461 "Exceeding time budget by "
462 << duration.toMilliSecondsDouble() <<
"ms.";
468 SelfCollisionChecker::_preFinishRunning()
471 ARMARX_INFO <<
"Stopping Self Collision Avoidance.";
472 if (selfCollisionAvoidanceThread.joinable())
474 selfCollisionAvoidanceThread.join();
Property< PropertyType > getProperty(const std::string &name)
static Frequency Hertz(std::int64_t hertz)
SpamFilterDataPtr deactivateSpam(float deactivationDurationSec=10.0f, const std::string &identifier="", bool deactivate=true) const
disables the logging for the current line for the given amount of seconds.
T & _module()
Returns this as ref to the given type.
void throwIfInControlThread(const std::string &fnc) const
Throws if the current thread is the ControlThread.
bool isShuttingDown() const
Returns whether the RobotUnit is shutting down.
bool isSelfCollisionCheckEnabled(const Ice::Current &=Ice::emptyCurrent) const override
Returns whether the frequency of self collision checks is above 0.
void setSelfCollisionAvoidanceDistance(Ice::Float distance, const Ice::Current &=Ice::emptyCurrent) override
Sets the minimal distance (mm) between a configured pair of bodies to 'distance'.
float getSelfCollisionAvoidanceFrequency(const Ice::Current &=Ice::emptyCurrent) const override
Returns the frequency of self collision checks.
float getSelfCollisionAvoidanceDistance(const Ice::Current &=Ice::emptyCurrent) const override
Returns the minimal distance (mm) between a pair of bodies.
void setSelfCollisionAvoidanceFrequency(Ice::Float freq, const Ice::Current &=Ice::emptyCurrent) override
Sets the frequency of self collision checks.
#define ARMARX_CHECK_GREATER(lhs, rhs)
This macro evaluates whether lhs is greater (>) than rhs and if it turns out to be false it will thro...
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
#define ARMARX_CHECK_EQUAL(lhs, rhs)
This macro evaluates whether lhs is equal (==) rhs and if it turns out to be false it will throw an E...
#define ARMARX_INFO
The normal logging level.
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
#define ARMARX_VERBOSE
The logging level for verbose information.
#define ARMARX_ON_SCOPE_EXIT
Executes given code when the enclosing scope is left.
std::vector< std::string > Split(const std::string &source, const std::string &splitBy, bool trimElements=false, bool removeEmptyElements=false)
double distance(const Point &a, const Point &b)