Skip to content

Commit 19a6d5f

Browse files
authored
feat: search straight path from waypoint to goal (#29)
1 parent 78cd2e6 commit 19a6d5f

File tree

4 files changed

+118
-1
lines changed

4 files changed

+118
-1
lines changed

include/smac_planner/a_star.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,16 @@ class AStarAlgorithm
125125
*/
126126
void setSearchBounds(const geometry_msgs::Pose& search_bounds, const geometry_msgs::Point& start_point, bool allow_goal_overshoot);
127127

128+
void setSearchStraightPathFlag(const bool search_straight_path);
129+
130+
131+
/**
132+
* @brief get straight path by interpolating points between start and goal, fails if any interpolated point is in collision.
133+
* @param path output path
134+
* @param cancel_checker Function to check if the task has been canceled
135+
*/
136+
uint32_t getStraightPath(CoordinateVector & path, std::function<bool()> cancel_checker);
137+
128138
/**
129139
* @brief Set the goal for planning, as a node index
130140
* @param mx The node X index of the goal

include/smac_planner/types.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ struct SearchInfo
5151
bool allow_goal_overshoot{true};
5252
bool downsample_obstacle_heuristic{true};
5353
bool use_quadratic_cost_penalty{false};
54+
bool search_straight_path{false};
5455
void setStart(const geometry_msgs::Point& start);
5556
geometry_msgs::Pose getSearchBound();
5657
void setSearchBound(const geometry_msgs::Pose& search_bound);

src/a_star.cpp

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,11 @@ void AStarAlgorithm<NodeT>::setSearchBounds(const geometry_msgs::Pose& search_bo
130130
_expander->setSearchBounds(search_bounds, start_point, allow_goal_overshoot);
131131
}
132132

133+
template <typename NodeT>
134+
void AStarAlgorithm<NodeT>::setSearchStraightPathFlag(const bool search_straight_path) {
135+
_search_info.search_straight_path = search_straight_path;
136+
}
137+
133138

134139
template<typename NodeT>
135140
typename AStarAlgorithm<NodeT>::NodePtr AStarAlgorithm<NodeT>::addToGraph(
@@ -292,6 +297,98 @@ bool AStarAlgorithm<NodeT>::areInputsValid()
292297
return true;
293298
}
294299

300+
template<typename NodeT>
301+
uint32_t AStarAlgorithm<NodeT>::getStraightPath(
302+
CoordinateVector & path,
303+
std::function<bool()> cancel_checker)
304+
{
305+
if (!areInputsValid()) {
306+
return mbf_msgs::GetPathResult::INTERNAL_ERROR;
307+
}
308+
309+
// Start coordinates differ for Node2D
310+
typename NodeT::Coordinates start_coords;
311+
if constexpr (std::is_same<NodeT, Node2D>::value) {
312+
start_coords = _start->getCoords(_start->getIndex());
313+
} else {
314+
start_coords = _start->pose;
315+
}
316+
317+
typename NodeT::Coordinates goal_coords = _goal_coordinates;
318+
319+
std::vector<Coordinates> path_coordinates;
320+
321+
// Add goal
322+
path_coordinates.push_back(goal_coords);
323+
324+
// Simple interpolation between start and goal
325+
const float dx = goal_coords.x - start_coords.x;
326+
const float dy = goal_coords.y - start_coords.y;
327+
const float steps = std::max(std::abs(dx), std::abs(dy));
328+
329+
// Add intermediate points along the straight line
330+
for (int i = 1; i < steps; ++i) {
331+
if (cancel_checker()) {
332+
return mbf_msgs::GetPathResult::CANCELED;
333+
}
334+
const float ratio = static_cast<float>(i) / steps;
335+
typename NodeT::Coordinates intermediate;
336+
intermediate.x = start_coords.x + dx * ratio;
337+
intermediate.y = start_coords.y + dy * ratio;
338+
339+
if constexpr (!std::is_same<NodeT, Node2D>::value) {
340+
// Only non-Node2D has theta
341+
intermediate.theta = start_coords.theta;
342+
}
343+
344+
unsigned int index;
345+
if constexpr (std::is_same<NodeT, Node2D>::value) {
346+
index = Node2D::getIndex(
347+
static_cast<unsigned int>(intermediate.x),
348+
static_cast<unsigned int>(intermediate.y),
349+
_costmap->getSizeInCellsX());
350+
} else {
351+
index = NodeT::getIndex(
352+
static_cast<unsigned int>(intermediate.x),
353+
static_cast<unsigned int>(intermediate.y),
354+
static_cast<unsigned int>(intermediate.theta));
355+
}
356+
357+
NodePtr node = addToGraph(index);
358+
359+
if constexpr (!std::is_same<NodeT, Node2D>::value) {
360+
node->setPose(intermediate);
361+
}
362+
363+
// Check if this node is valid
364+
if (!node->isNodeValid(_traverse_unknown, _collision_checker)) {
365+
double map_x, map_y;
366+
_costmap->mapToWorld(
367+
static_cast<unsigned int>(intermediate.x),
368+
static_cast<unsigned int>(intermediate.y),
369+
map_x, map_y);
370+
ROS_ERROR_NAMED("smac_planner",
371+
"Fail to plan straight path because point at (%.2f, %.2f) is in collision", map_x, map_y);
372+
return mbf_msgs::GetPathResult::NO_PATH_FOUND;
373+
}
374+
375+
path_coordinates.push_back(intermediate);
376+
}
377+
378+
// Add start
379+
path_coordinates.push_back(start_coords);
380+
381+
if constexpr (!std::is_same<NodeT, Node2D>::value) {
382+
for (auto & coord : path_coordinates) {
383+
coord.theta = NodeT::motion_table.getAngleFromBin(coord.theta);
384+
}
385+
}
386+
387+
path = std::move(path_coordinates);
388+
return mbf_msgs::GetPathResult::SUCCESS;
389+
}
390+
391+
295392
template<typename NodeT>
296393
uint32_t AStarAlgorithm<NodeT>::createPath(
297394
CoordinateVector & path, int & iterations,
@@ -308,6 +405,12 @@ uint32_t AStarAlgorithm<NodeT>::createPath(
308405
return mbf_msgs::GetPathResult::INTERNAL_ERROR;
309406
}
310407

408+
// Check if we should use straight path
409+
if (_search_info.search_straight_path) {
410+
return getStraightPath(path, cancel_checker);
411+
}
412+
413+
311414
// 0) Add starting point to the open set
312415
addNode(0.0, getStart());
313416
getStart()->setAccumulatedCost(0.0);

src/smac_planner_hybrid.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,12 @@ PlanResult SmacPlannerHybrid::planWithWaypoint(
185185
_a_star->setSearchBounds(goal_pose.pose, waypoint.pose.position, _search_info.allow_goal_overshoot);
186186
}
187187

188-
// waypoint to goal pose
188+
// waypoint to goal pose (search_straight_path = true for this segment)
189189
PlanResult segment2;
190+
_a_star->setSearchStraightPathFlag(true);
190191
getPath(waypoint, goal_pose, tolerance, segment2);
192+
_a_star->setSearchStraightPathFlag(false);
193+
191194
if (!segment2.isValid())
192195
{
193196
ROS_ERROR_NAMED("smac_planner_hybrid", "Could not find path from waypoint to goal, with error: %s",

0 commit comments

Comments
 (0)