33#include <boost/geometry/algorithms/convex_hull.hpp>
34#include <boost/geometry/algorithms/disjoint.hpp>
35#include <boost/geometry/geometries/box.hpp>
37#include <SimoxUtility/meta/enum/EnumNames.hpp>
38#include <VirtualRobot/CollisionDetection/CollisionChecker.h>
39#include <VirtualRobot/CollisionDetection/CollisionModel.h>
40#include <VirtualRobot/Nodes/RobotNode.h>
41#include <VirtualRobot/Robot.h>
42#include <VirtualRobot/RobotFactory.h>
43#include <VirtualRobot/SceneObjectSet.h>
44#include <VirtualRobot/VirtualRobot.h>
62#if COSTMAP_BUILDER_SIMOX_CONTROL
63#include <simox/control/environment/CollisionRobot.h>
64#include <simox/control/impl/simox/robot/Robot.h>
65#include <simox/control/impl/simox/utils/conversion.h>
67#include <hpp/fcl/broadphase/broadphase_dynamic_AABB_tree.h>
73#if COSTMAP_BUILDER_SIMOX_CONTROL
74 namespace sc = simox::control;
79 template <
class... Ts>
82 using Ts::operator()...;
85 template <
class... Ts>
88 const simox::meta::EnumNames<CostmapBuilder::DistanceCalculator>
94 const VirtualRobot::SceneObjectSetPtr& obstacles,
95 const std::vector<VirtualRobot::RobotPtr>& articulatedObjects,
96 const std::vector<Room>& rooms,
98 const std::string& robotCollisonModelName,
101 obstacles(obstacles),
102 articulatedObjects(articulatedObjects),
104 parameters(parameters),
105 robotCollisionModelName(robotCollisonModelName),
106 builderParameters(builderParameters)
110 ARMARX_CHECK(robot->hasRobotNode(robotCollisionModelName));
114 const auto& enabledRooms = this->builderParameters.
roomEnableList;
115 if (not enabledRooms.empty())
118 this->rooms.erase(std::remove_if(this->rooms.begin(),
120 [&enabledRooms](
const Room& room)
122 const bool roomIncluded =
123 std::find(enabledRooms.cbegin(),
125 room.name) != enabledRooms.cend();
126 if (not roomIncluded)
129 <<
"Room " << room.name
130 <<
" was found but is not included";
132 return not roomIncluded;
137 if (builderParameters.restrictToRooms)
140 <<
"No rooms enabled, even though restrict to rooms is true";
149 {
ARMARX_INFO <<
"Creating costmap took " << duration; });
151 ARMARX_INFO << articulatedObjects.size() <<
" articulated objects";
158 parameters.sceneBoundsMargin,
159 builderParameters.restrictToRooms);
165 if (builderParameters.restrictToRooms)
171 for (
const auto& room : rooms)
178 ARMARX_VERBOSE <<
"Restricted to rooms. Fraction of valid elements: "
185 {
ARMARX_INFO <<
"Filling costmap took " << duration; });
188 <<
costmap.getGrid().cols() <<
") and resolution "
205 {
ARMARX_INFO <<
"Extending costmap took " << duration; });
207 if (builderParameters.restrictToRooms)
217 {
ARMARX_INFO <<
"Filling costmap took " << duration; });
220 <<
costmap.getGrid().cols() <<
") and resolution "
247 ARMARX_VERBOSE <<
"Initializing empty mask: Fraction of valid elements: "
260 size_t c_x = (sceneBounds.
max.x() - sceneBounds.
min.x()) / parameters.cellSize + 1;
261 size_t c_y = (sceneBounds.
max.y() - sceneBounds.
min.y()) / parameters.cellSize + 1;
266 Eigen::MatrixXf grid(c_x, c_y);
274 const CollisionSetup& collisionSetupVariant)
276 float cost = std::visit(
278 [&position](
const CollisionSetupSC& collisionSetup) ->
float
281#if COSTMAP_BUILDER_SIMOX_CONTROL
288 collisionSetup.robot->setGlobalPose(
289 sc::simox::utils::from_simox(globalPose.matrix()),
true);
291 collisionSetup.collisionRobot->update();
293 for (
const auto& o : collisionSetup.colObjects)
299 collisionSetup.collisionRobot->getCollisionManager()->update();
300 collisionSetup.obstacleCollisionManager->update();
302 hpp::fcl::DistanceCallBackDefault defaultCallback;
303 collisionSetup.obstacleCollisionManager->distance(
304 collisionSetup.collisionRobot->getCollisionManager(), &defaultCallback);
306 const double minDistance = defaultCallback.data.result.min_distance;
308 return static_cast<float>(std::max(minDistance, 0.) * 1000);
311 <<
"SimoxControl distance calculation requested but not supported. "
312 "Please compile with SimoxControl to use this calculation method.";
316 [&position,
this](
const CollisionSetupSx& collisionSetup) ->
float
318 const auto& collisionRobot = collisionSetup.collisionRobot;
319 const auto& robotCollisionModel = collisionSetup.robotCollisionModel;
325 VirtualRobot::CollisionChecker::getGlobalCollisionChecker());
327 const VirtualRobot::SceneObjectSetPtr& actualObstacles = [&]()
329 if (collisionSetup.filteredObstacles)
331 return collisionSetup.filteredObstacles;
335 return this->obstacles;
341 collisionRobot->setGlobalPose(globalPose.matrix());
344 float distanceNonArticulated = std::numeric_limits<float>::max();
345 if (actualObstacles->getSize() > 0)
347 distanceNonArticulated =
348 VirtualRobot::CollisionChecker::getGlobalCollisionChecker()
349 ->calculateDistance(robotCollisionModel, actualObstacles);
353 float distanceArticulatedMin = std::numeric_limits<float>::max();
354 for (
const auto& articulatedObject : articulatedObjects)
356 for (
const auto& colModel : articulatedObject->getCollisionModels())
358 const float distanceArticulated =
359 VirtualRobot::CollisionChecker::getGlobalCollisionChecker()
360 ->calculateDistance(robotCollisionModel, colModel);
361 distanceArticulatedMin =
362 std::min(distanceArticulated, distanceArticulatedMin);
366 return std::min(distanceNonArticulated, distanceArticulatedMin);
412 [](
const std::monostate& _) ->
float
417 collisionSetupVariant);
420 cost = std::min(cost, builderParameters.maxDistance);
425 CostmapBuilder::fillGridCosts(Costmap& costmap)
427 applyFnToCostmap(costmap,
428 [&](
const CollisionSetup& collisionSetup,
429 const std::optional<float> maskOpt,
431 const Costmap::Index&
index) ->
float
433 const auto position = costmap.toPositionGlobal(
index);
436 if (maskOpt.has_value())
438 if (not maskOpt.value())
445 if( builderParameters.fakeModeForTesting)
447 return builderParameters.maxDistance;
450 return computeCost(position, collisionSetup);
455 CostmapBuilder::extendGridCosts(Costmap& costmap)
459 [&](
const CollisionSetup& collisionSetup,
460 const std::optional<float> maskOpt,
462 const Costmap::Index&
index) ->
float
464 const auto position = costmap.toPositionGlobal(
index);
468 if (maskOpt.has_value())
470 if (not maskOpt.value())
472 return std::min(0.F, cost);
481 return std::min(cost, computeCost(position, collisionSetup));
486 CostmapBuilder::applyFnToCostmap(Costmap& costmap,
487 const std::function<
float(
const CollisionSetup& collisionSetup,
488 const std::optional<float>,
490 const Costmap::Index&)>& fn)
494 const VirtualRobot::SceneObjectSetPtr filteredObjects = filterObjectsForCostmap(costmap);
497 const auto initializeCollisionSetup = [&]() -> CollisionSetup
499 armarx::core::time::ScopedStopWatch sw(
500 [](
const armarx::core::time::Duration& duration)
502 ARMARX_INFO <<
"Initializing collision setup on thread " << omp_get_thread_num()
503 <<
" took: " << duration;
506 switch (builderParameters.calculationMethod)
508 case DistanceCalculator::SimoxControl:
510#if COSTMAP_BUILDER_SIMOX_CONTROL
512 CollisionSetupSC collisionSetup;
514 using ScRobot = sc::simox::robot::Robot;
515 using ScCollisionRobot = sc::environment::CollisionRobot<hpp::fcl::OBBRSS>;
521 robot->clone(
"collision_robot_" + std::to_string(omp_get_thread_num()));
525 clonedRobot->setPrimitiveApproximationModel({
"navigation"},
false);
527 clonedRobot->setUpdateVisualization(
false);
530 collisionSetup.robot = ScRobot::CREATE_SIMPLE_WRAPPER(clonedRobot);
532 collisionSetup.collisionRobot =
533 std::make_unique<ScCollisionRobot>(*collisionSetup.robot,
536 std::vector<std::string>{
"navigation"});
538 collisionSetup.obstacleCollisionManager =
539 std::make_unique<hpp::fcl::DynamicAABBTreeCollisionManager>();
541 const auto convertVRObstacle =
544 const auto& obstacle = collisionSetup.scObstacles.emplace_back(
545 ScRobot::CREATE_SIMPLE_WRAPPER(r));
549 const auto& colObject = collisionSetup.colObjects.emplace_back(
550 std::make_unique<ScCollisionRobot>(*obstacle));
553 for (
auto& node : colObject->getNodes())
555 for (std::size_t i = 0; i < node.size(); i++)
557 collisionSetup.obstacleCollisionManager->registerObject(
558 &node.getColObject(i));
562 catch (
const std::exception& ex)
566 <<
"` to collision robot.\n"
572 for (
const auto& o : this->obstacles->getSceneObjects())
576 std::dynamic_pointer_cast<VirtualRobot::GraspableSensorizedObject>(o);
578 <<
"Scene object is not a graspable sensorized object";
580 VirtualRobot::RobotFactory::createRobot(*casted);
581 convertVRObstacle(asRobot);
585 for (
const auto& o : this->articulatedObjects)
587 convertVRObstacle(o);
592 ARMARX_INFO <<
"Converted " << collisionSetup.colObjects.size() <<
"/"
596 collisionSetup.obstacleCollisionManager->setup();
598 return collisionSetup;
601 <<
"SimoxControl distance calculation requested but not supported. "
602 "Please compile with SimoxControl to use this calculation method.";
606 case DistanceCalculator::Simox:
608 CollisionSetupSx collisionSetup;
612 collisionSetup.collisionRobot =
613 robot->clone(
"collision_robot_" + std::to_string(omp_get_thread_num()));
616 collisionSetup.collisionRobot->setPrimitiveApproximationModel({
"navigation"},
619 collisionSetup.collisionRobot->setUpdateVisualization(
false);
624 collisionSetup.collisionRobot->hasRobotNode(robotCollisionModelName));
626 const auto collisionRobotNode =
627 collisionSetup.collisionRobot->getRobotNode(robotCollisionModelName);
630 collisionSetup.robotCollisionModel = collisionRobotNode->getCollisionModel();
632 <<
"Collision model not available. "
633 "Make sure that you load the robot correctly!";
636 collisionSetup.robotCollisionModel->scale(
637 builderParameters.collisionModelScaleFactor);
639 collisionSetup.filteredObstacles = filteredObjects;
644 return collisionSetup;
647 ARMARX_ERROR <<
"Invalid distance calculator specified";
652 if (costmap.mask.has_value())
657 const std::size_t c_x = costmap.grid.rows();
658 const std::size_t c_y = costmap.grid.cols();
660 robot->setUpdateVisualization(
false);
663 CollisionSetup collisionSetup;
665 const int threadNumDefault = omp_get_max_threads();
666 const int actualThreads = this->builderParameters.numThreads == 0
668 : this->builderParameters.numThreads;
669 ARMARX_INFO <<
"Using " << actualThreads <<
" threads.";
672#pragma omp parallel for num_threads(actualThreads) \
673 schedule(static) private(collisionSetup) default(shared)
674 for (
unsigned int x = 0; x < c_x; x++)
681 if (std::holds_alternative<std::monostate>(collisionSetup))
683 collisionSetup = initializeCollisionSetup();
686 ARMARX_CHECK(not std::holds_alternative<std::monostate>(collisionSetup));
689 for (
unsigned int y = 0; y < c_y; y++)
691 const Costmap::Index
index{x, y};
693 const auto maskVal = costmap.mask.has_value()
694 ? std::make_optional(costmap.mask.value()(x, y))
696 costmap.grid(x, y) = fn(collisionSetup, maskVal, costmap.grid(x, y),
index);
699 catch (
const std::exception& e)
701 ARMARX_ERROR <<
"Error during costmap calculation: " << e.what();
706 VirtualRobot::SceneObjectSetPtr
707 CostmapBuilder::filterObjectsForCostmap(
const Costmap& costmap)
709 armarx::core::time::ScopedStopWatch sw(
710 [](
const armarx::core::time::Duration& duration)
711 {
ARMARX_INFO <<
"Filtering objects took " << duration; });
713 VirtualRobot::SceneObjectSetPtr filtered(
new VirtualRobot::SceneObjectSet);
716 using Box = boost::geometry::model::box<Point>;
719 const auto toPoint = [](
const Eigen::Vector3f& vec) {
return Point(vec.x(), vec.y()); };
720 const auto toBox = [&
toPoint](
const VirtualRobot::BoundingBox& bb)
726 costmap.toPositionGlobal(Costmap::Index(0, 0)),
727 costmap.toPositionGlobal(Costmap::Index(0, costmap.grid.cols() - 1)),
728 costmap.toPositionGlobal(Costmap::Index(costmap.grid.rows() - 1, 0)),
729 costmap.toPositionGlobal(
730 Costmap::Index(costmap.grid.rows() - 1, costmap.grid.cols() - 1))});
731 boost::geometry::convex_hull(cornerPoints, costmapBB);
735 for (
const auto&
object : this->obstacles->getSceneObjects())
737 const auto& colModel =
object->getCollisionModel();
741 Box bb = toBox(colModel->getGlobalBoundingBox());
745 if (boost::geometry::disjoint(costmapBB, bb))
747 float distance = boost::geometry::distance(costmapBB, bb);
748 if (
distance > builderParameters.maxFilterDistance)
755 filtered->addSceneObject(
object);
758 const std::size_t prevSize = this->obstacles->getSize();
759 const std::size_t filteredSize = filtered->getSize();
761 ARMARX_INFO <<
"Remaining objects for costmap calculation: " << filteredSize <<
"/"
763 <<
static_cast<float>(filteredSize) * 100.f /
static_cast<float>(prevSize)
766 for (
const auto&
object : filtered->getSceneObjects())
#define ARMARX_CHECK_NOT_EMPTY(c)
Measures the time this stop watch was inside the current scope.
static const simox::meta::EnumNames< DistanceCalculator > DistanceCalculatorNames
static Eigen::MatrixXf createUniformGrid(const SceneBounds &sceneBounds, const Costmap::Parameters ¶meters)
Costmap extend(Costmap costmap)
CostmapBuilder(const VirtualRobot::RobotPtr &robot, const VirtualRobot::SceneObjectSetPtr &obstacles, const std::vector< VirtualRobot::RobotPtr > &articulatedObjects, const std::vector< Room > &rooms, const Costmap::Parameters ¶meters, const std::string &robotCollisonModelName, const CostmapBuilderParams &builderParameters)
Costmap create(const SceneBounds &init=SceneBounds())
static void updateMask(Costmap &costmap)
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#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_NONNEGATIVE(number)
Check whether number is nonnegative (>= 0).
#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_VERBOSE
The logging level for verbose information.
std::shared_ptr< class Robot > RobotPtr
This file is part of ArmarX.
This file is part of ArmarX.
overloaded(Ts...) -> overloaded< Ts... >
SceneBounds computeSceneBounds(const VirtualRobot::SceneObjectSetPtr &obstacles, const std::vector< VirtualRobot::RobotPtr > &articulatedObjects, const SceneBounds &init, const std::vector< Room > &rooms, const float margin, const bool restrictToRooms)
void invalidateOutsideRooms(const std::vector< Room > &rooms, Costmap &costmap)
std::vector< Eigen::Vector3f > to3D(const std::vector< Eigen::Vector2f > &v)
boost::geometry::model::d2::point_xy< float > point_type
point_type toPoint(const Eigen::Vector2f &pt)
polygon_type toPolygon(const std::vector< Eigen::Vector2f > &hull)
boost::geometry::model::polygon< point_type > polygon_type
objpose::ObjectPoseSeq articulatedObjects(objpose::ObjectPoseSeq objects)
::wykobi::polygon< float, 2 > Polygon
double distance(const Point &a, const Point &b)
std::vector< std::string > roomEnableList