33#include <VirtualRobot/CollisionDetection/CollisionModel.h>
34#include <VirtualRobot/Nodes/RobotNode.h>
35#include <VirtualRobot/Robot.h>
36#include <VirtualRobot/SceneObjectSet.h>
37#include <VirtualRobot/VirtualRobot.h>
59 const VirtualRobot::SceneObjectSetPtr& obstacles,
60 const std::vector<VirtualRobot::RobotPtr>& articulatedObjects,
61 const std::vector<Room>& rooms,
63 const std::string& robotCollisonModelName,
67 articulatedObjects(articulatedObjects),
69 parameters(parameters),
70 robotCollisionModelName(robotCollisonModelName),
71 builderParameters(builderParameters)
76 if (not robotCollisonModelName.empty())
78 ARMARX_CHECK(robot->hasRobotNode(robotCollisionModelName)) << robotCollisionModelName;
81 if (not parameters.robotModel.rootNode.empty())
83 ARMARX_INFO <<
"Using alternative root node " <<
QUOTED(parameters.robotModel.rootNode);
84 auto node = robot->getRobotNode(parameters.robotModel.rootNode);
87 const Eigen::Isometry3f root_T_used_root(node->getPoseInRootFrame());
91 <<
"Nodes must be at the same hight.";
93 const Eigen::Matrix3f R = root_T_used_root.linear();
97 const float a = Eigen::Vector3f{R.row(2)}.dot(Eigen::Vector3f::UnitZ());
99 const float b = Eigen::Vector3f{R.col(2)}.dot(Eigen::Vector3f::UnitZ());
108 root_T_used_root_2d = Eigen::Isometry2f::Identity();
110 root_T_used_root_2d.translation() = root_T_used_root.translation().head<2>();
112 root_T_used_root_2d.linear() = R.topLeftCorner<2, 2>();
118 root_T_used_root_2d = root_T_used_root_2d.inverse();
120 ARMARX_INFO <<
"Root transform: " << root_T_used_root_2d.matrix();
124 const auto& enabledRooms = this->builderParameters.
roomEnableList;
126 for (
const auto& room : this->rooms)
132 if (not enabledRooms.empty())
135 this->rooms.erase(std::remove_if(this->rooms.begin(),
137 [&enabledRooms](
const Room& room)
139 const bool roomIncluded =
140 std::find(enabledRooms.cbegin(),
142 room.name) != enabledRooms.cend();
143 if (not roomIncluded)
146 <<
"Room " << room.name
147 <<
" was found but is not included";
149 return not roomIncluded;
154 if (builderParameters.restrictToRooms)
157 <<
"No rooms enabled, even though restrict to rooms is true";
166 {
ARMARX_INFO <<
"Creating Costmap3D took " << duration; });
171 std::optional<Costmap3D> inflatedCostmap;
175 {
ARMARX_INFO <<
"Filling Costmap3D took " << duration; });
178 <<
costmap.getGrid().cols() <<
") and resolution "
181 inflatedCostmap.emplace(inflateRotationDimension(
costmap));
183 if (builderParameters.restrictToRooms)
186 extendGridCosts(*inflatedCostmap, rooms);
190 extendGridCosts(*inflatedCostmap, {});
199 return inflatedCostmap.value();
207 {
ARMARX_INFO <<
"Creating Costmap3D took " << duration; });
209 ARMARX_INFO << articulatedObjects.size() <<
" articulated objects";
216 parameters.sceneBoundsMargin,
217 builderParameters.restrictToRooms);
223 if (builderParameters.restrictToRooms)
229 for (
const auto& room : rooms)
236 ARMARX_VERBOSE <<
"Restricted to rooms. Fraction of valid elements: "
243 {
ARMARX_INFO <<
"Filling Costmap3D took " << duration; });
246 <<
costmap.getGrid()[0].cols() <<
"/rot" <<
costmap.params().orientations
247 <<
") and resolution " <<
costmap.params().cellSize;
266 ARMARX_VERBOSE <<
"Initializing mask: Fraction of valid elements: "
270 std::optional<Costmap3DBuilder::DebugOutput2D>
273 return debugOutput2D;
284 ARMARX_VERBOSE <<
"Initializing empty mask: Fraction of valid elements: "
293 grid.reserve(parameters.orientations);
294 for (
int i = 0; i < parameters.orientations; ++i)
311 size_t c_x = (sceneBounds.
max.x() - sceneBounds.
min.x()) / parameters.cellSize + 1;
312 size_t c_y = (sceneBounds.
max.y() - sceneBounds.
min.y()) / parameters.cellSize + 1;
317 Eigen::MatrixXf grid(c_x, c_y);
324 Costmap3DBuilder::computeCost(
const core::Pose2D& global_T_root,
328 const core::Pose2D global_T_used_root = global_T_root * root_T_used_root_2d;
339 std::vector<Costmap::Grid> new_grid;
340 new_grid.reserve(parameters.orientations);
341 for (
int i = 0; i < parameters.orientations; ++i)
343 new_grid.push_back(
costmap.getGrid());
346 Costmap3D costmap3d{new_grid,
355 Costmap3DBuilder::fillGridCosts2D(Costmap3D& costmap)
357 filteredObstacles = filterObjectsForCostmap(costmap);
358 const auto fn = [&](
const MapStructRobot2D& m) ->
float
360 const auto degrees = costmap.rotationFromIndex(m.c.rotIdx).degrees;
361 const auto pose = costmap.globalPose(m.c.posIdx, degrees);
362 ARMARX_CHECK(costmap.rotationDegrees(pose) - degrees < 0.001)
363 <<
"Rotation degrees do not match: " << costmap.rotationDegrees(pose)
364 <<
" != " << degrees;
365 if (m.c.isMaskedOut())
369 float distance = computeCost(pose, m.robot, m.scene);
370 if (
distance < builderParameters.obstacleSafetyMargin)
381 Costmap3DBuilder::fillGridCosts(Costmap3D&
costmap)
383 filteredObstacles = filterObjectsForCostmap(
costmap);
385 if (builderParameters.approximation2D)
391 const auto fn = [&](
const MapStruct& m) ->
float
394 costmap.globalPose(m.c.posIdx,
costmap.rotationFromIndex(m.c.rotIdx).degrees);
395 if (m.c.isMaskedOut())
399 float distance = m.distanceCalculator.distanceToObstacles(pose);
400 if (
distance < builderParameters.obstacleSafetyMargin)
411 Costmap3DBuilder::extendGridCosts(Costmap3D&
costmap,
const std::vector<Room>& rooms)
418 Costmap3DBuilder::applyFnToCostmap(Costmap3D&
costmap,
const MapFn& fn)
420 SceneRepresentation sceneRepresentation{.staticObjects = filteredObstacles,
422 DistanceCalculator distanceCalculator{sceneRepresentation};
430 const std::size_t c_x =
costmap.grid[0].rows();
431 const std::size_t c_y =
costmap.grid[0].cols();
433 robot->setUpdateVisualization(
false);
435#pragma omp parallel for schedule(static) firstprivate(distanceCalculator) default(shared)
436 for (
unsigned int x = 0; x < c_x; x++)
439 if (not distanceCalculator.isRobotInitialized())
442 distanceCalculator.initializeRobot(
444 Robot3D::Params{.collisionModelName = robotCollisionModelName,
445 .scaleFactor = builderParameters.collisionModelScaleFactor,
446 .primitiveApproximationIDs =
447 builderParameters.primitiveApproximationIDs,
448 .rootNode = parameters.robotModel.rootNode});
452 for (
unsigned int y = 0; y < c_y; y++)
454 for (
int rot_idx = 0; rot_idx < parameters.orientations; rot_idx++)
456 const Costmap3D::Index
index{x, y};
458 const auto maskVal =
costmap.mask.has_value()
459 ? std::make_optional(
costmap.mask.value()(x, y))
465 .cost =
costmap.grid[rot_idx](x, y),
469 .distanceCalculator = distanceCalculator,
471 costmap.grid[rot_idx](x, y) = fn(m);
478 Costmap3DBuilder::applyFnToCostmap(Costmap3D&
costmap,
const MapFnRobot2D& fn)
480 Robot3D distanceRobot = Robot3D::fromSimoxRobot(
482 Robot3D::Params{.collisionModelName = robotCollisionModelName,
483 .scaleFactor = builderParameters.collisionModelScaleFactor,
484 .primitiveApproximationIDs =
485 builderParameters.primitiveApproximationIDs,
486 .rootNode =
costmap.parameters.robotModel.rootNode});
488 <<
"Robot3D is not initialized. Make sure to call initializeRobot() before using it!";
489 Robot2D robot2d{distanceRobot.robot, distanceRobot.collisionModels};
491 SceneRepresentation scene3d{
492 .staticObjects = filteredObstacles,
495 Scene2D scene2d{scene3d, builderParameters.approx2DignoreVerticesOver};
497 this->debugOutput2D = {
498 .robot = robot2d, .scene = scene2d, .root_T_used_root_2d = root_T_used_root_2d};
506 const std::size_t c_x =
costmap.grid[0].rows();
507 const std::size_t c_y =
costmap.grid[0].cols();
509 robot->setUpdateVisualization(
false);
511#pragma omp parallel for schedule(static) shared(robot2d) default(shared)
512 for (
unsigned int x = 0; x < c_x; x++)
514 for (
unsigned int y = 0; y < c_y; y++)
516 for (
int rot_idx = 0; rot_idx < parameters.orientations; rot_idx++)
518 const Costmap3D::Index
index{x, y};
520 const auto maskVal =
costmap.mask.has_value()
521 ? std::make_optional(
costmap.mask.value()(x, y))
524 const MapStructRobot2D m{
527 .cost =
costmap.grid[rot_idx](x, y),
534 costmap.grid[rot_idx](x, y) = fn(m);
540 VirtualRobot::SceneObjectSetPtr
541 Costmap3DBuilder::filterObjectsForCostmap(
const Costmap3D&
costmap)
543 armarx::core::time::ScopedStopWatch sw(
544 [](
const armarx::core::time::Duration& duration)
545 {
ARMARX_INFO <<
"Filtering objects took " << duration; });
547 VirtualRobot::SceneObjectSetPtr filtered(
new VirtualRobot::SceneObjectSet);
550 using Box = boost::geometry::model::box<Point>;
553 const auto toPoint = [](
const Eigen::Vector3f& vec) {
return Point(vec.x(), vec.y()); };
554 const auto toBox = [&
toPoint](
const VirtualRobot::BoundingBox& bb)
566 boost::geometry::convex_hull(cornerPoints, costmapBB);
570 for (
const auto&
object : this->obstacles->getSceneObjects())
572 const auto& colModel =
object->getCollisionModel();
576 Box bb = toBox(colModel->getGlobalBoundingBox());
580 if (boost::geometry::disjoint(costmapBB, bb))
582 float distance = boost::geometry::distance(costmapBB, bb);
583 if (
distance > builderParameters.maxFilterDistance)
590 filtered->addSceneObject(
object);
593 const auto prevSize = this->obstacles->getSize();
594 const auto filteredSize = filtered->getSize();
596 ARMARX_INFO <<
"Remaining objects for costmap calculation: " << filteredSize <<
"/"
597 << prevSize <<
" (" << filteredSize * 100 /
static_cast<float>(prevSize) <<
"%)";
599 for (
const auto&
object : filtered->getSceneObjects())
#define ARMARX_CHECK_NOT_EMPTY(c)
Measures the time this stop watch was inside the current scope.
const core::Pose2D & origin() const
const SceneBounds & getLocalSceneBounds() const noexcept
const std::optional< Mask > & getMask() const noexcept
static Eigen::MatrixXf createUniformGridSingleOrientation(const SceneBounds &sceneBounds, const Costmap3D::Parameters ¶meters)
std::optional< DebugOutput2D > getDebugOutput2D()
Costmap3D create(const SceneBounds &init=SceneBounds())
static void initializeMask(Costmap3D &costmap)
Costmap3DBuilder(const VirtualRobot::RobotPtr &robot, const VirtualRobot::SceneObjectSetPtr &obstacles, const std::vector< VirtualRobot::RobotPtr > &articulatedObjects, const std::vector< Room > &rooms, const Costmap3D::Parameters ¶meters, const std::string &robotCollisonModelName, const Costmap3DBuilderParams &builderParameters)
Costmap3D extend(Costmap costmap)
static Costmap3D::Grid createUniformGrid(const SceneBounds &sceneBounds, const Costmap3D::Parameters ¶meters)
std::vector< Eigen::MatrixXf > Grid
CollisionPolygon getRobotAtPose(const core::Pose2D &pose) const
float distance(const CollisionPolygon &robot) const
#define ARMARX_CHECK_CLOSE(lhs, rhs, prec)
Check whether lhs is close to rhs, i.e.
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#define ARMARX_CHECK_LESS(lhs, rhs)
This macro evaluates whether lhs is less (<) than rhs and if it turns out to be false it will throw a...
#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_INFO
The normal logging level.
#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.
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)
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