42 initialize(rows, cols, orientations,
costmap);
48 for (
int r = 0; r < rows; r++)
50 for (
int c = 0;
c < cols;
c++)
52 for (
int rot_idx = 0; rot_idx < orientations; rot_idx++)
67 return data_[((row * cols) + col) * orientations + orientation];
71 Grid::initialize(
int rows,
int cols,
int orientations,
const Costmap3D&
costmap)
76 this->orientations = orientations;
84 data_ = std::make_unique<Node[]>(rows * cols * orientations);
87 for (
int r = 0; r < rows; r++)
89 for (
int c = 0;
c < cols;
c++)
91 for (
int rot_idx = 0; rot_idx < orientations; rot_idx++)
93 const auto pos =
costmap.toPositionGlobal({r,
c});
94 const float obstacleDistance =
costmap.value_ignore_mask(
96 const auto rotation_deg =
110 for (
int r = 0; r < rows; r++)
112 for (
int c = 0;
c < cols;
c++)
114 for (
int rot_idx = 0; rot_idx < orientations; rot_idx++)
116 Node& candidate =
getNode(r,
c, rot_idx);
123 for (
int nR = -1; nR <= 1; nR++)
125 for (
int nC = -1; nC <= 1; nC++)
127 const int neighborIndexC =
c + nC;
128 const int neighborIndexR = r + nR;
129 if (neighborIndexC < 0 || neighborIndexR < 0 || (nR == 0 && nC == 0))
134 if (neighborIndexR >=
static_cast<int>(rows) ||
135 neighborIndexC >=
static_cast<int>(cols))
142 for (
int nRot = -3; nRot <= 3; nRot++)
144 int neighborRotIndex = rot_idx + nRot;
145 if (neighborRotIndex < 0)
147 neighborRotIndex += orientations;
149 if (neighborRotIndex >= orientations)
151 neighborRotIndex -= orientations;
153 getNode(neighborIndexR, neighborIndexC, neighborRotIndex)
160 bool enableRotationInPlace =
162 for (
int nRot = -1; enableRotationInPlace && nRot <= 1; nRot++)
168 int neighborRotIndex = rot_idx + nRot;
169 if (neighborRotIndex < 0)
171 neighborRotIndex += orientations;
173 if (neighborRotIndex >= orientations)
175 neighborRotIndex -= orientations;
184 ARMARX_VERBOSE <<
"Grid created in " << (t2 - t1).toMilliSeconds() <<
" ms";
193 return not
costmap.isInCollision(n.position,
194 costmap.closestRotationFromDegrees(n.orientation_deg));
198 costmap3d(costmap3d), params(params)
203 AStarPlanner::heuristic(
const Node& n1,
const Node& n2)
217 float rot_deg = Eigen::Rotation2Df{pose.rotation()}.angle() * 180.F /
M_PI;
224 const auto vertex = costmap3d.
toVertex(pose.translation());
226 ARMARX_DEBUG <<
"Closest rotation: " << rot.index <<
" (" << rot.degrees <<
" deg)";
228 const int r = vertex.index.x();
229 const int c = vertex.index.y();
235 const int rows =
static_cast<int>(costmap3d.
getSize().
x());
236 const int cols =
static_cast<int>(costmap3d.
getSize().y());
242 return grid->getNode(
static_cast<int>(r),
static_cast<int>(
c), rot.index);
249 angleBetween(
const Eigen::Vector2f& a,
const Eigen::Vector2f& b)
251 float dotProd = a.dot(b);
252 float magA = a.norm();
253 float magB = b.norm();
255 if (magA == 0.0f || magB == 0.0f)
261 float cosTheta = dotProd / (magA * magB);
266 if (cosTheta < -1.0f)
269 return std::acos(cosTheta);
273 smoothnessCosts(
const Node& n1,
275 const std::optional<Node>& n3,
276 const std::optional<Node>& n4)
284 const Eigen::Vector2f v21 = n1.position - n2.position;
285 const Eigen::Vector2f v23 = n3.value().position - n2.position;
286 float angle = std::abs(angleBetween(v21, -v23));
288 cost += angle_to_cost(
angle);
290 if (
false && n3.has_value() && n4.has_value())
292 const Eigen::Vector2f v32 = n2.position - n3.value().position;
293 const Eigen::Vector2f v34 = n4.value().position - n3.value().position;
294 float angle = angleBetween(v32, -v34);
296 cost += angle_to_cost(
angle);
302 std::vector<core::Pose2D>
307 if (grid.has_value())
314 const auto size = costmap3d.getSize();
315 grid = {size.x(), size.y(), costmap3d.params().orientations, costmap3d};
317 std::vector<core::Pose2D> result;
319 ARMARX_DEBUG <<
"Setting start node for position " << start.matrix();
320 Node& nodeStart = closestNode(start);
323 << costmap3d.closestRotationFromDegrees(nodeStart.
orientation_deg).index;
326 ARMARX_DEBUG <<
"Setting goal node for position " << goal.matrix();
327 Node& nodeGoal = closestNode(goal);
330 << costmap3d.closestRotationFromDegrees(nodeGoal.
orientation_deg).index;
337 nodeStart.
fScore = nodeStart.
gScore + heuristic(nodeStart, nodeGoal);
340 auto cmp = [&](
const Node* left,
const Node* right)
341 {
return left->fScore > right->fScore; };
342 std::priority_queue<Node*, std::vector<Node*>,
decltype(cmp)> openSetPq(cmp);
343 openSetPq.push(&nodeStart);
346 bool foundSolution =
false;
347 while (!openSetPq.empty())
349 Node& currentBest = *openSetPq.top();
352 if (¤tBest == &nodeGoal)
354 foundSolution =
true;
359 for (
size_t i = 0; i < currentBest.
successors.size(); i++)
370 cost = costs(currentBest, neighbor);
372 catch (
const std::exception& e)
374 ARMARX_ERROR <<
"Cost calculation failed for neighbor at position "
375 << neighbor.
position.transpose() <<
" with orientation "
384 const auto pred2 = pred1.has_value()
386 ? std::make_optional(*(pred1->predecessor))
390 smoothnessCosts(neighbor, currentBest, pred1, pred2);
396 neighbor.
gScore = tentativeGScore;
397 neighbor.
fScore = tentativeGScore + heuristic(neighbor, nodeGoal);
400 openSetPq.push(&neighbor);
411 result = resultNodes |
412 ranges::views::transform(
413 [
this](
const Node* node)
noexcept {
414 return costmap3d.globalPose(costmap3d.toVertex(node->
position).index,
418 auto predecessorCosts = resultNodes |
419 ranges::views::transform([](
const Node* node)
noexcept
422 ranges::reverse(predecessorCosts);
424 Costs combinedCosts = {};
425 for (
const auto&
c : predecessorCosts)
428 if (not
c.has_value())
438 combinedCosts = combinedCosts +
c.value();
453 ranges::reverse(result);
459 AStarPlanner::costs(
const Node& n1,
const Node& n2)
const
469 const float obstacleProximityChangeCosts = obstacleDistanceN1 - obstacleDistanceN2;
475 const float obstacleProximityN2CostsNormalized =
484 auto ori_vec_n1 = pose_n1.linear() * Eigen::Vector2f::UnitY();
485 auto ori_vec_n2 = pose_n2.linear() * Eigen::Vector2f::UnitY();
486 Eigen::Vector2f ori_vec = ori_vec_n1 + ori_vec_n2;
488 const Eigen::Vector2f vectorDiff_norm = vectorDiff.normalized();
489 float forward_angle = 0;
490 if (vectorDiff.norm() == 0.F)
492 ARMARX_DEBUG <<
"Zero-length vector between nodes, cannot calculate forward movement "
493 "cost. n1 position: "
499 forward_angle = std::abs(angleBetween(ori_vec, -vectorDiff_norm));
505 .obstacleProximity2 =