Skip to content

Commit c716ae8

Browse files
committed
rrt star working
1 parent a965ea6 commit c716ae8

8 files changed

Lines changed: 1156 additions & 0 deletions

File tree

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
cmake_minimum_required(VERSION 3.20)
2+
project(easynav_gridmap_rrtstar_planner)
3+
4+
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
5+
add_compile_options(-Wall -Wextra -Wpedantic)
6+
endif()
7+
8+
set(CMAKE_CXX_STANDARD 23)
9+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
10+
set(CMAKE_CXX_EXTENSIONS OFF)
11+
12+
find_package(ament_cmake REQUIRED)
13+
find_package(easynav_common REQUIRED)
14+
find_package(easynav_core REQUIRED)
15+
find_package(pluginlib REQUIRED)
16+
find_package(nav_msgs REQUIRED)
17+
find_package(grid_map_ros REQUIRED)
18+
find_package(grid_map_msgs REQUIRED)
19+
20+
add_library(${PROJECT_NAME} SHARED
21+
src/easynav_gridmap_rrtstar_planner/GridMapRRTStarPlanner.cpp
22+
src/easynav_gridmap_rrtstar_planner/KDTree.cpp
23+
)
24+
target_include_directories(${PROJECT_NAME} PUBLIC
25+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
26+
$<INSTALL_INTERFACE:include/${PROJECT_NAME}>
27+
)
28+
target_link_libraries(${PROJECT_NAME} PUBLIC
29+
easynav_common::easynav_common
30+
easynav_core::easynav_core
31+
pluginlib::pluginlib
32+
grid_map_ros::grid_map_ros
33+
${nav_msgs_TARGETS}
34+
${grid_map_msgs_TARGETS}
35+
)
36+
37+
install(
38+
DIRECTORY include/
39+
DESTINATION include/${PROJECT_NAME}
40+
)
41+
42+
install(TARGETS
43+
${PROJECT_NAME}
44+
EXPORT export_${PROJECT_NAME}
45+
ARCHIVE DESTINATION lib
46+
LIBRARY DESTINATION lib
47+
RUNTIME DESTINATION lib/${PROJECT_NAME}
48+
)
49+
50+
if(BUILD_TESTING)
51+
find_package(ament_lint_auto REQUIRED)
52+
set(ament_cmake_copyright_FOUND TRUE)
53+
set(ament_cmake_cpplint_FOUND TRUE)
54+
ament_lint_auto_find_test_dependencies()
55+
56+
find_package(ament_cmake_gtest REQUIRED)
57+
# add_subdirectory(tests)
58+
endif()
59+
60+
ament_export_include_directories("include/${PROJECT_NAME}")
61+
ament_export_libraries(${PROJECT_NAME})
62+
ament_export_targets(export_${PROJECT_NAME})
63+
64+
# Register the planning plugins
65+
pluginlib_export_plugin_description_file(easynav_core easynav_gridmap_rrtstar_planner_plugins.xml)
66+
67+
ament_export_dependencies(
68+
easynav_common
69+
easynav_core
70+
easynav_simple_common
71+
pluginlib
72+
nav_msgs
73+
grid_map_ros
74+
grid_map_msgs
75+
)
76+
ament_package()
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<class_libraries>
2+
<library path="easynav_gridmap_rrtstar_planner">
3+
<class name="easynav_gridmap_rrtstar_planner/GridMapRRTStarPlanner" type="easynav::GridMapRRTStarPlanner" base_class_type="easynav::PlannerMethodBase">
4+
<description>
5+
A implementation for the RRT* path planner.
6+
</description>
7+
</class>
8+
</library>
9+
</class_libraries>
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
// Copyright 2025 Intelligent Robotics Lab
2+
//
3+
// This file is part of the project Easy Navigation (EasyNav in short)
4+
// licensed under the GNU General Public License v3.0.
5+
// See <http://www.gnu.org/licenses/> for details.
6+
//
7+
// Easy Navigation program is free software: you can redistribute it and/or modify
8+
// it under the terms of the GNU General Public License as published by
9+
// the Free Software Foundation, either version 3 of the License, or
10+
// (at your option) any later version.
11+
//
12+
// This program is distributed in the hope that it will be useful,
13+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
// GNU General Public License for more details.
16+
//
17+
// You should have received a copy of the GNU General Public License
18+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
20+
/// \file
21+
/// \brief Declaration of the GridMapRRTStarPlanner class implementing RRT* path planning using elevation maps.
22+
23+
#ifndef EASYNAV_GRIDMAP_RRTSTAR_PLANNER__GRIDMAPRRTSTARPLANNER_HPP_
24+
#define EASYNAV_GRIDMAP_RRTSTAR_PLANNER__GRIDMAPRRTSTARPLANNER_HPP_
25+
26+
#include <cmath>
27+
#include <limits>
28+
#include <sstream>
29+
#include <algorithm>
30+
#include <random>
31+
#include <queue>
32+
#include <unordered_set>
33+
#include <unordered_map>
34+
#include <memory>
35+
36+
#include "grid_map_core/GridMap.hpp"
37+
#include "nav_msgs/msg/goals.hpp"
38+
#include "nav_msgs/msg/odometry.hpp"
39+
#include "nav_msgs/msg/path.hpp"
40+
#include "rclcpp/rclcpp.hpp"
41+
#include "easynav_core/PlannerMethodBase.hpp"
42+
#include "easynav_gridmap_rrtstar_planner/KDTree.hpp"
43+
#include "easynav_gridmap_rrtstar_planner/RRTNode.hpp"
44+
#include "tf2/LinearMath/Quaternion.hpp"
45+
#include "tf2_geometry_msgs/tf2_geometry_msgs.hpp"
46+
47+
namespace easynav
48+
{
49+
50+
class KDTree;
51+
52+
/**
53+
* @brief RRT* planner implementation using a grid map with elevation support.
54+
*
55+
* This planner generates collision-free paths that respect slope constraints.
56+
* It includes RRT* optimizations, KD-tree acceleration, and path smoothing.
57+
*/
58+
class GridMapRRTStarPlanner : public PlannerMethodBase
59+
{
60+
public:
61+
/**
62+
* @brief Constructor.
63+
* Initializes the KD-tree and sets default parameters.
64+
*/
65+
GridMapRRTStarPlanner();
66+
67+
/**
68+
* @brief Initializes the planner plugin.
69+
* Declares and retrieves parameters from the ROS2 node.
70+
* @return std::expected<void, std::string> Empty if successful, error message if failed.
71+
*/
72+
std::expected<void, std::string> on_initialize() override;
73+
74+
/**
75+
* @brief Main planner update function.
76+
* Computes a path from the robot to the goal each cycle.
77+
* Publishes the path and visualization markers if there are subscribers.
78+
* @param nav_state Navigation state containing robot pose, map, and goals.
79+
*/
80+
void update(NavState & nav_state) override;
81+
82+
protected:
83+
/**
84+
* @brief Runs RRT* algorithm to generate a path from start to goal.
85+
* @param map Grid map used for planning.
86+
* @param start Start pose in the map frame.
87+
* @param goal Goal pose in the map frame.
88+
* @return Vector of smoothed poses representing the planned path.
89+
* @note Path will be empty if start or goal is outside map bounds.
90+
*/
91+
std::vector<geometry_msgs::msg::Pose> rrt_star(
92+
const grid_map::GridMap & map,
93+
const geometry_msgs::msg::Pose & start,
94+
const geometry_msgs::msg::Pose & goal);
95+
96+
/**
97+
* @brief Generates a random index inside the map.
98+
* @param map Grid map to sample from.
99+
* @param rng Random number generator.
100+
* @return Random index within map bounds.
101+
*/
102+
grid_map::Index random_index(const grid_map::GridMap & map, std::mt19937 & rng);
103+
104+
/**
105+
* @brief Steers from one index towards another with a maximum step size.
106+
* @param map Grid map used for distance conversion.
107+
* @param from Starting index.
108+
* @param to Target index.
109+
* @return New index reached after stepping, or {-1,-1} if outside map.
110+
*/
111+
grid_map::Index steer(
112+
const grid_map::GridMap & map, const grid_map::Index & from,
113+
const grid_map::Index & to);
114+
115+
/**
116+
* @brief Computes traversal cost between two indices, considering elevation and slope.
117+
* @param map Grid map used for cost evaluation.
118+
* @param to Destination index.
119+
* @param from Source index.
120+
* @return Traversal cost. Returns infinity if the path is invalid or slope exceeds max allowed.
121+
*/
122+
double traversal_cost(
123+
const grid_map::GridMap & map, const grid_map::Index & to,
124+
const grid_map::Index & from);
125+
126+
/**
127+
* @brief Computes Euclidean distance between two indices.
128+
* @param map Grid map used to convert indices to positions.
129+
* @param a First index.
130+
* @param b Second index.
131+
* @return Euclidean distance in meters.
132+
*/
133+
double distance(
134+
const grid_map::GridMap & map, const grid_map::Index & a,
135+
const grid_map::Index & b);
136+
137+
/**
138+
* @brief Extracts path poses from a goal node back to the start node.
139+
* @param node Goal node of RRT* tree.
140+
* @param map Grid map used for position extraction.
141+
* @param goal Goal pose for final orientation.
142+
* @return Vector of poses representing the path.
143+
*/
144+
std::vector<geometry_msgs::msg::Pose> extract_path(
145+
std::shared_ptr<RRTNode> node,
146+
const grid_map::GridMap & map,
147+
const geometry_msgs::msg::Pose & goal);
148+
149+
/**
150+
* @brief Finds the nearest node in the tree to a target index.
151+
* @param tree Vector of RRT nodes.
152+
* @param target Index to find nearest node to.
153+
* @param map Grid map used to compute distance.
154+
* @return Shared pointer to nearest node, or nullptr if tree is empty.
155+
*/
156+
std::shared_ptr<RRTNode> find_nearest(
157+
const std::vector<std::shared_ptr<RRTNode>> & tree,
158+
const grid_map::Index & target,
159+
const grid_map::GridMap & map);
160+
161+
/**
162+
* @brief Generates a biased sample index for RRT* exploration.
163+
* @param map Grid map used for sampling.
164+
* @param goal_idx Index of the goal.
165+
* @param best_goal_node Best goal node found so far (used for path-biased sampling).
166+
* @param rng Random number generator.
167+
* @param prob_dist Probability distribution for random sampling.
168+
* @return Index sampled for RRT* expansion.
169+
*/
170+
grid_map::Index generate_sample(
171+
const grid_map::GridMap & map,
172+
const grid_map::Index & goal_idx,
173+
std::shared_ptr<RRTNode> best_goal_node,
174+
std::mt19937 & rng,
175+
std::uniform_real_distribution<double> & prob_dist);
176+
177+
/**
178+
* @brief Smooths a path using Catmull-Rom splines.
179+
* @param input_path Input path to smooth.
180+
* @param interpolation_points_per_segment Number of interpolated points per segment.
181+
* @return Smoothed path as a vector of poses.
182+
* @note Spacing between consecutive points is enforced by `spacing_`.
183+
*/
184+
std::vector<geometry_msgs::msg::Pose> smooth_path(
185+
const std::vector<geometry_msgs::msg::Pose> & input_path,
186+
int interpolation_points_per_segment);
187+
188+
// -----------------------
189+
// Planner parameters
190+
// -----------------------
191+
double max_allowed_slope_deg_ = 50; ///< Maximum slope in degrees
192+
double max_allowed_slope_ = 50.0 * M_PI / 180.0; ///< Maximum slope in radians
193+
int max_iters_ = 2000; ///< Maximum RRT* iterations
194+
double step_size_ = 0.8; ///< Maximum step distance (m)
195+
double neighbor_radius_ = 1.5; ///< RRT* neighbor radius (m)
196+
double goal_bias_ = 0.1; ///< Probability of sampling the goal
197+
double goal_threshold_ = 1.0; ///< Distance threshold for goal connection (m)
198+
int kdtree_rebuild_interval_ = 200; ///< Interval to rebuild KD-tree
199+
double spacing_ = 0.2; ///< Minimum spacing for smoothed path points (m)
200+
201+
// -----------------------
202+
// Runtime state
203+
// -----------------------
204+
rclcpp::Publisher<nav_msgs::msg::Path>::SharedPtr path_pub_; ///< Path publisher
205+
nav_msgs::msg::Path current_path_; ///< Current planned path
206+
std::unique_ptr<KDTree> kd_tree_; ///< KD-tree for nearest neighbor search
207+
std::unordered_map<uint64_t, double> cost_cache_; ///< Cache for traversal costs
208+
uint32_t cached_map_width_ = 0;
209+
uint32_t cached_map_height_ = 0;
210+
uint64_t last_map_timestamp_ = 0;
211+
212+
// -----------------------
213+
// Cache utilities
214+
// -----------------------
215+
void clear_cost_cache();
216+
static uint32_t flat_index(const grid_map::Index & idx, uint32_t width);
217+
static uint64_t edge_key(uint32_t a_flat, uint32_t b_flat);
218+
};
219+
220+
} // namespace easynav
221+
222+
#endif // EASYNAV_GRIDMAP_RRTSTAR_PLANNER__GRIDMAPRRTSTARPLANNER_HPP_

0 commit comments

Comments
 (0)