lanelet2_route_planning v2.0.0
Loading...
Searching...
No Matches
plan_route_action_client::PlanRouteActionClient Class Reference

Action client node for planning a route. More...

#include <plan_route_action_client.hpp>

Inheritance diagram for plan_route_action_client::PlanRouteActionClient:

Public Member Functions

 PlanRouteActionClient ()
 Constructor.
 

Private Types

using PlanRoute = route_planning_msgs::action::PlanRoute
 
using GoalHandlePlanRoute = rclcpp_action::ClientGoalHandle<PlanRoute>
 

Private Member Functions

template<typename T >
void declareAndLoadParameter (const std::string &name, T &param, const std::string &description, const bool add_to_auto_reconfigurable_params=true, const bool is_required=false, const bool read_only=false, const std::optional< double > &from_value=std::nullopt, const std::optional< double > &to_value=std::nullopt, const std::optional< double > &step_value=std::nullopt, const std::string &additional_constraints="")
 Declares and loads a ROS parameter.
 
rcl_interfaces::msg::SetParametersResult parametersCallback (const std::vector< rclcpp::Parameter > &parameters)
 Handles reconfiguration when a parameter value is changed.
 
void setup ()
 Sets up subscribers, publishers, etc. to configure the node.
 
void goalPoseCallback (const geometry_msgs::msg::PoseStamped::SharedPtr msg)
 Callback for goal pose (most likely received from RViz)
 
void autoPlanningTimerCallback ()
 Callback for automatically planning a route, e.g., if waypoints are given.
 
void planToNextWaypoint ()
 Plans to next waypoint.
 
void planToRandomDestination ()
 Plans to a random destination.
 
void sendGoal (const geometry_msgs::msg::PoseStamped::SharedPtr msg, const std::vector< geometry_msgs::msg::PointStamped > &intermediate_destinations={})
 Sends a goal to the action server.
 
void goalResponseCallback (const GoalHandlePlanRoute::SharedPtr &goal_handle)
 Callback for goal response from the action server.
 
void feedbackCallback (GoalHandlePlanRoute::SharedPtr goal_handle, const std::shared_ptr< const PlanRoute::Feedback > feedback)
 Callback for feedback from the action server.
 
void resultCallback (const GoalHandlePlanRoute::WrappedResult &result)
 Callback for result from the action server.
 

Private Attributes

std::vector< std::tuple< std::string, std::function< void(const rclcpp::Parameter &)> > > auto_reconfigurable_params_
 Auto-reconfigurable parameters for dynamic reconfiguration.
 
OnSetParametersCallbackHandle::SharedPtr parameters_callback_
 Callback handle for dynamic parameter reconfiguration.
 
rclcpp::Subscription< geometry_msgs::msg::PoseStamped >::SharedPtr goal_pose_subscriber_
 Subscriber for goal pose.
 
rclcpp_action::Client< PlanRoute >::SharedPtr action_client_
 Action client.
 
std::shared_future< GoalHandlePlanRoute::SharedPtr > goal_handle_future_
 Goal handle.
 
rclcpp::TimerBase::SharedPtr auto_planning_timer_
 Timer to automatically plan route, e.g., if waypoints are given.
 
std::unique_ptr< Lanelet2MapInterface > ll2_interface_
 Lanelet2 map interface.
 
std::vector< std::pair< double, double > > waypoints_
 WGS84 waypoints to endlessly follow.
 
std::vector< double > waypoint_wait_times_
 Wait time for each waypoint [s]; negative values mark intermediate destinations.
 
size_t next_waypoint_idx_ = 0
 Index of next waypoint to follow.
 
bool has_active_waypoint_ = false
 Whether the active goal belongs to the waypoint list.
 
double active_waypoint_wait_time_s_ = 0.0
 Wait time of the active waypoint [s].
 
double auto_planning_resume_time_s_ = 0.0
 Earliest wall-clock time at which automatic planning may continue.
 
bool has_completed_one_goal_ = false
 Whether one goal has been completed (succeeded or failed)
 
std::string ll2_map_server_name_ = "ll2_map_server"
 Name of lanelet2_map_server node (parameter)
 
std::vector< std::string > waypoints_param_
 WGS84 waypoints to endlessly follow (parameter)
 
bool enable_random_destination_ = false
 Whether to plan a route to a random destination (parameter)
 
bool enable_continuous_planning_ = false
 Whether to continuously plan a new route (parameter)
 
bool cancel_route_ = false
 Flag to cancel the route planning action (parameter)
 

Detailed Description

Action client node for planning a route.

Definition at line 33 of file plan_route_action_client.hpp.

Member Typedef Documentation

◆ GoalHandlePlanRoute

using plan_route_action_client::PlanRouteActionClient::GoalHandlePlanRoute = rclcpp_action::ClientGoalHandle<PlanRoute>
private

Definition at line 35 of file plan_route_action_client.hpp.

◆ PlanRoute

using plan_route_action_client::PlanRouteActionClient::PlanRoute = route_planning_msgs::action::PlanRoute
private

Definition at line 34 of file plan_route_action_client.hpp.

Constructor & Destructor Documentation

◆ PlanRouteActionClient()

plan_route_action_client::PlanRouteActionClient::PlanRouteActionClient ( )

Constructor.

Definition at line 67 of file plan_route_action_client.cpp.

67 : Node("plan_route_action_client") {
68 this->declareAndLoadParameter("ll2_map_server_name", ll2_map_server_name_, "Name of lanelet2_map_server node", false);
70 "waypoints", waypoints_param_,
71 "List of WGS84 waypoints to follow (list of strings with comma-separated '<LATITUDE>,<LONGITUDE>[,<WAIT_TIME_S>]', missing "
72 "wait time defaults to 0s, negative wait time means intermediate destination)",
73 true);
74 this->declareAndLoadParameter("enable_random_destination", enable_random_destination_,
75 "Whether to plan a route to a random destination", true);
76 this->declareAndLoadParameter("enable_continuous_planning", enable_continuous_planning_,
77 "Whether to continuously plan a new route (either looping waypoints or to a random destination)",
78 true);
79 this->declareAndLoadParameter("cancel_route", cancel_route_, "Cancel active route planning action (to be set at runtime)",
80 true);
81 this->setup();
82}
bool cancel_route_
Flag to cancel the route planning action (parameter)
bool enable_continuous_planning_
Whether to continuously plan a new route (parameter)
std::string ll2_map_server_name_
Name of lanelet2_map_server node (parameter)
std::vector< std::string > waypoints_param_
WGS84 waypoints to endlessly follow (parameter)
bool enable_random_destination_
Whether to plan a route to a random destination (parameter)
void setup()
Sets up subscribers, publishers, etc. to configure the node.
void declareAndLoadParameter(const std::string &name, T &param, const std::string &description, const bool add_to_auto_reconfigurable_params=true, const bool is_required=false, const bool read_only=false, const std::optional< double > &from_value=std::nullopt, const std::optional< double > &to_value=std::nullopt, const std::optional< double > &step_value=std::nullopt, const std::string &additional_constraints="")
Declares and loads a ROS parameter.

Member Function Documentation

◆ autoPlanningTimerCallback()

void plan_route_action_client::PlanRouteActionClient::autoPlanningTimerCallback ( )
private

Callback for automatically planning a route, e.g., if waypoints are given.

Does nothing, if no waypoints are given and random planning is disabled. Precedence: random planning, waypoints

Definition at line 243 of file plan_route_action_client.cpp.

243 {
244 const double now_s = std::chrono::duration<double>(std::chrono::steady_clock::now().time_since_epoch()).count();
245 if (now_s < auto_planning_resume_time_s_) {
246 return;
247 }
248
251 } else if (!waypoints_.empty()) {
253 next_waypoint_idx_ = 0; // loop waypoints, if continuous planning is enabled
254 }
255 if (next_waypoint_idx_ < waypoints_.size()) {
256 this->planToNextWaypoint();
257 }
258 } else {
259 RCLCPP_DEBUG(this->get_logger(), "Nothing to plan, waiting for waypoints or random destination");
260 }
261}
size_t next_waypoint_idx_
Index of next waypoint to follow.
void planToRandomDestination()
Plans to a random destination.
double auto_planning_resume_time_s_
Earliest wall-clock time at which automatic planning may continue.
std::vector< std::pair< double, double > > waypoints_
WGS84 waypoints to endlessly follow.
bool has_completed_one_goal_
Whether one goal has been completed (succeeded or failed)

◆ declareAndLoadParameter()

template<typename T >
void plan_route_action_client::PlanRouteActionClient::declareAndLoadParameter ( const std::string & name,
T & param,
const std::string & description,
const bool add_to_auto_reconfigurable_params = true,
const bool is_required = false,
const bool read_only = false,
const std::optional< double > & from_value = std::nullopt,
const std::optional< double > & to_value = std::nullopt,
const std::optional< double > & step_value = std::nullopt,
const std::string & additional_constraints = "" )
private

Declares and loads a ROS parameter.

Parameters
[in]namename
[in]paramparameter variable to load into
[in]descriptiondescription
[in]add_to_auto_reconfigurable_paramsenable reconfiguration of parameter
[in]is_requiredwhether failure to load parameter will stop node
[in]read_onlyset parameter to read-only
[in]from_valueparameter range minimum
[in]to_valueparameter range maximum
[in]step_valueparameter range step
[in]additional_constraintsadditional constraints description

Definition at line 85 of file plan_route_action_client.cpp.

94 {
95 rcl_interfaces::msg::ParameterDescriptor param_desc;
96 param_desc.description = description;
97 param_desc.additional_constraints = additional_constraints;
98 param_desc.read_only = read_only;
99
100 auto type = rclcpp::ParameterValue(param).get_type();
101
102 if (from_value.has_value() && to_value.has_value()) {
103 if constexpr (std::is_integral_v<T>) {
104 rcl_interfaces::msg::IntegerRange range;
105 T step = static_cast<T>(step_value.has_value() ? step_value.value() : 1);
106 range.set__from_value(static_cast<T>(from_value.value())).set__to_value(static_cast<T>(to_value.value())).set__step(step);
107 param_desc.integer_range = {range};
108 } else if constexpr (std::is_floating_point_v<T>) {
109 rcl_interfaces::msg::FloatingPointRange range;
110 T step = static_cast<T>(step_value.has_value() ? step_value.value() : 1.0);
111 range.set__from_value(static_cast<T>(from_value.value())).set__to_value(static_cast<T>(to_value.value())).set__step(step);
112 param_desc.floating_point_range = {range};
113 } else {
114 RCLCPP_WARN(this->get_logger(), "Parameter type of parameter '%s' does not support specifying a range", name.c_str());
115 }
116 }
117
118 this->declare_parameter(name, type, param_desc);
119
120 try {
121 param = this->get_parameter(name).get_value<T>();
122 std::stringstream ss;
123 ss << "Loaded parameter '" << name << "': ";
124 if constexpr (is_vector_v<T>) {
125 ss << "[";
126 for (const auto& element : param) ss << element << (&element != &param.back() ? ", " : "]");
127 } else {
128 ss << param;
129 }
130 RCLCPP_INFO_STREAM(this->get_logger(), ss.str());
131 } catch (rclcpp::exceptions::ParameterUninitializedException&) {
132 if (is_required) {
133 RCLCPP_FATAL_STREAM(this->get_logger(), "Missing required parameter '" << name << "', exiting");
134 exit(EXIT_FAILURE);
135 } else {
136 std::stringstream ss;
137 ss << "Missing parameter '" << name << "', using default value: ";
138 if constexpr (is_vector_v<T>) {
139 ss << "[";
140 for (const auto& element : param) ss << element << (&element != &param.back() ? ", " : "]");
141 } else {
142 ss << param;
143 }
144 RCLCPP_WARN_STREAM(this->get_logger(), ss.str());
145 this->set_parameters({rclcpp::Parameter(name, rclcpp::ParameterValue(param))});
146 }
147 }
148
149 if (add_to_auto_reconfigurable_params) {
150 std::function<void(const rclcpp::Parameter&)> setter = [&param](const rclcpp::Parameter& p) { param = p.get_value<T>(); };
151 auto_reconfigurable_params_.push_back(std::make_tuple(name, setter));
152 }
153}
std::vector< std::tuple< std::string, std::function< void(const rclcpp::Parameter &)> > > auto_reconfigurable_params_
Auto-reconfigurable parameters for dynamic reconfiguration.

◆ feedbackCallback()

void plan_route_action_client::PlanRouteActionClient::feedbackCallback ( GoalHandlePlanRoute::SharedPtr goal_handle,
const std::shared_ptr< const PlanRoute::Feedback > feedback )
private

Callback for feedback from the action server.

Parameters
[in]goal_handlegoal handle
[in]feedbackaction feedback

Definition at line 429 of file plan_route_action_client.cpp.

430 {
431 (void)goal_handle;
432
433 const double distance_traveled = feedback->distance_traveled;
434 const double distance_total = feedback->distance_remaining + feedback->distance_traveled;
435 rclcpp::Duration time_traveled(feedback->time_traveled.sec, feedback->time_traveled.nanosec);
436 rclcpp::Duration time_remaining(feedback->time_remaining.sec, feedback->time_remaining.nanosec);
437 rclcpp::Duration time_total = time_traveled + time_remaining;
438 RCLCPP_INFO(this->get_logger(), "Route progress: %.2f / %.2f m, %.1f / %.1f s", distance_traveled, distance_total,
439 time_traveled.seconds(), time_total.seconds());
440}

◆ goalPoseCallback()

void plan_route_action_client::PlanRouteActionClient::goalPoseCallback ( const geometry_msgs::msg::PoseStamped::SharedPtr msg)
private

Callback for goal pose (most likely received from RViz)

Parameters
[in]msggoal pose

Definition at line 234 of file plan_route_action_client.cpp.

234 {
235 RCLCPP_INFO(this->get_logger(), "Received goal pose (%.3f, %.3f, %.3f) in frame '%s'", msg->pose.position.x,
236 msg->pose.position.y, msg->pose.position.z, msg->header.frame_id.c_str());
237 has_active_waypoint_ = false;
240 sendGoal(msg);
241}
double active_waypoint_wait_time_s_
Wait time of the active waypoint [s].
bool has_active_waypoint_
Whether the active goal belongs to the waypoint list.
void sendGoal(const geometry_msgs::msg::PoseStamped::SharedPtr msg, const std::vector< geometry_msgs::msg::PointStamped > &intermediate_destinations={})
Sends a goal to the action server.

◆ goalResponseCallback()

void plan_route_action_client::PlanRouteActionClient::goalResponseCallback ( const GoalHandlePlanRoute::SharedPtr & goal_handle)
private

Callback for goal response from the action server.

Parameters
[in]goal_handlegoal handle

Definition at line 419 of file plan_route_action_client.cpp.

419 {
420 if (!goal_handle) {
421 RCLCPP_ERROR(this->get_logger(), "Goal rejected by action server");
422 has_active_waypoint_ = false;
423 auto_planning_timer_->reset(); // restart auto-planning timer
424 } else {
425 RCLCPP_INFO(this->get_logger(), "Goal accepted by action server");
426 }
427}
rclcpp::TimerBase::SharedPtr auto_planning_timer_
Timer to automatically plan route, e.g., if waypoints are given.

◆ parametersCallback()

rcl_interfaces::msg::SetParametersResult plan_route_action_client::PlanRouteActionClient::parametersCallback ( const std::vector< rclcpp::Parameter > & parameters)
private

Handles reconfiguration when a parameter value is changed.

Parameters
[in]parametersparameters
Returns
parameter change result

Definition at line 155 of file plan_route_action_client.cpp.

156 {
157 for (const auto& param : parameters) {
158 for (auto& auto_reconfigurable_param : auto_reconfigurable_params_) {
159 if (param.get_name() == std::get<0>(auto_reconfigurable_param)) {
160 std::get<1>(auto_reconfigurable_param)(param);
161 RCLCPP_INFO(this->get_logger(), "Reconfigured parameter '%s'", param.get_name().c_str());
162 break;
163 }
164 }
165
166 // handle waypoints
167 if (param.get_name() == "waypoints") {
168 auto parsed_waypoints = parseWaypoints(waypoints_param_, waypoint_wait_times_, this->get_logger());
169 if (parsed_waypoints) {
170 waypoints_ = *parsed_waypoints;
171 } else {
172 std::stringstream ss;
173 ss << "Failed to parse parameter 'waypoints': [";
174 for (const auto& waypoint : waypoints_param_) {
175 ss << waypoint << (&waypoint != &waypoints_param_.back() ? ", " : "]");
176 }
177 RCLCPP_ERROR(this->get_logger(), "%s", ss.str().c_str());
178 }
179 }
180
181 // handle cancel_route
182 if (param.get_name() == "cancel_route") {
183 if (cancel_route_) {
184 if (action_client_->wait_for_action_server(std::chrono::duration<double>(0.1))) {
185 RCLCPP_INFO(this->get_logger(), "Cancelling route");
186 action_client_->async_cancel_all_goals();
187 } else {
188 RCLCPP_WARN(this->get_logger(), "Action server not available, cannot cancel route");
189 }
190 }
191 }
192 }
193
194 rcl_interfaces::msg::SetParametersResult result;
195 result.successful = true;
196
197 return result;
198}
std::vector< double > waypoint_wait_times_
Wait time for each waypoint [s]; negative values mark intermediate destinations.
rclcpp_action::Client< PlanRoute >::SharedPtr action_client_
Action client.
std::optional< std::vector< std::pair< double, double > > > parseWaypoints(const std::vector< std::string > &waypoints_param, std::vector< double > &waypoint_wait_times, const rclcpp::Logger &logger)
Parses WGS84 waypoints from "<LATITUDE>,<LONGITUDE>[,<WAIT_TIME_S>]" strings.

◆ planToNextWaypoint()

void plan_route_action_client::PlanRouteActionClient::planToNextWaypoint ( )
private

Plans to next waypoint.

Definition at line 263 of file plan_route_action_client.cpp.

263 {
264 // check if waypoint is valid
265 if (next_waypoint_idx_ >= waypoints_.size()) {
266 RCLCPP_ERROR(this->get_logger(), "Waypoint index %ld out of bounds (%ld), skipping", next_waypoint_idx_, waypoints_.size());
267 return;
268 }
269 if (waypoint_wait_times_.size() != waypoints_.size()) {
270 RCLCPP_ERROR(this->get_logger(), "Waypoint wait times do not match waypoints, skipping");
271 return;
272 }
273
274 // check if map is loaded
275 if (!ll2_interface_->map_loaded_) {
276 RCLCPP_ERROR(this->get_logger(), "Map not loaded, cannot generate waypoint");
277 return;
278 }
279
280 // generate goal pose from waypoint
281 auto goal_pose = std::make_shared<geometry_msgs::msg::PoseStamped>();
282 std::vector<geometry_msgs::msg::PointStamped> intermediate_destinations;
283 auto ll2_projector = ll2_interface_->getProjectorPtr();
284 if (!ll2_projector) {
285 RCLCPP_ERROR(this->get_logger(), "Failed to generate waypoint goal pose");
286 return;
287 }
288
289 size_t checked_waypoints = 0;
290 while (checked_waypoints < waypoints_.size()) {
291 const auto& waypoint = waypoints_[next_waypoint_idx_];
292 const double wait_time_s = waypoint_wait_times_[next_waypoint_idx_];
293 lanelet::GPSPoint gps_waypoint;
294 gps_waypoint.lat = waypoint.first;
295 gps_waypoint.lon = waypoint.second;
296 lanelet::BasicPoint3d map_waypoint = ll2_projector->forward(gps_waypoint);
297
298 geometry_msgs::msg::PointStamped waypoint_point;
299 waypoint_point.header.frame_id = ll2_interface_->map_frame_id_;
300 waypoint_point.header.stamp = this->now();
301 waypoint_point.point.x = map_waypoint.x();
302 waypoint_point.point.y = map_waypoint.y();
303 waypoint_point.point.z = 0.0;
304
305 if (wait_time_s < 0.0) {
306 RCLCPP_INFO(this->get_logger(), "Adding intermediate waypoint (%.6f, %.6f)", waypoint.first, waypoint.second);
307 intermediate_destinations.push_back(waypoint_point);
309 if (next_waypoint_idx_ >= waypoints_.size()) {
312 } else {
313 RCLCPP_ERROR(this->get_logger(), "No destination waypoint found after intermediate waypoints");
314 return;
315 }
316 }
317 checked_waypoints++;
318 continue;
319 }
320
321 RCLCPP_INFO(this->get_logger(), "Planning route to next waypoint (%.6f, %.6f)", waypoint.first, waypoint.second);
322 goal_pose->pose.position = waypoint_point.point;
323 goal_pose->header = waypoint_point.header;
324 active_waypoint_wait_time_s_ = wait_time_s;
326 break;
327 }
328
329 // send goal
330 if (!goal_pose->header.frame_id.empty()) {
331 RCLCPP_INFO(this->get_logger(), "Generated waypoint goal pose (%.3f, %.3f, %.3f) in frame '%s'", goal_pose->pose.position.x,
332 goal_pose->pose.position.y, goal_pose->pose.position.z, goal_pose->header.frame_id.c_str());
333 auto_planning_timer_->cancel(); // cancel auto-planning timer until goal completion
335 this->sendGoal(goal_pose, intermediate_destinations);
336 } else {
337 RCLCPP_ERROR(this->get_logger(), "Failed to generate waypoint goal pose");
338 }
339}
std::unique_ptr< Lanelet2MapInterface > ll2_interface_
Lanelet2 map interface.

◆ planToRandomDestination()

void plan_route_action_client::PlanRouteActionClient::planToRandomDestination ( )
private

Plans to a random destination.

Definition at line 341 of file plan_route_action_client.cpp.

341 {
342 RCLCPP_INFO(this->get_logger(), "Planning route to random destination");
343
344 // check if map is loaded
345 if (!ll2_interface_->map_loaded_) {
346 RCLCPP_ERROR(this->get_logger(), "Map not loaded, cannot generate a random destination");
347 return;
348 }
349
350 // generate random goal pose by sampling a random lanelet
351 auto goal_pose = std::make_shared<geometry_msgs::msg::PoseStamped>();
352 lanelet::LaneletMapConstPtr map = ll2_interface_->getMapPtr();
353 if (!map->laneletLayer.empty()) {
354 const auto lanelet_count = static_cast<int>(map->laneletLayer.size());
355 const auto random_lanelet_idx =
356 static_cast<std::iterator_traits<decltype(map->laneletLayer.begin())>::difference_type>(std::rand() % lanelet_count);
357 auto random_lanelet = *std::next(map->laneletLayer.begin(), random_lanelet_idx);
358 auto centerline = random_lanelet.centerline();
359 if (!centerline.empty()) {
360 auto point = centerline.back();
361 goal_pose->pose.position.x = point.x();
362 goal_pose->pose.position.y = point.y();
363 goal_pose->pose.position.z = point.z();
364 if (centerline.size() > 1) {
365 auto heading =
366 std::atan2(point.y() - centerline[centerline.size() - 2].y(), point.x() - centerline[centerline.size() - 2].x());
367 tf2::Quaternion q;
368 q.setRPY(0, 0, heading);
369 goal_pose->pose.orientation = tf2::toMsg(q);
370 }
371 goal_pose->header.frame_id = ll2_interface_->map_frame_id_;
372 goal_pose->header.stamp = this->now();
373 }
374 }
375
376 // send goal
377 if (!goal_pose->header.frame_id.empty()) {
378 RCLCPP_INFO(this->get_logger(), "Generated random goal pose (%.3f, %.3f, %.3f) in frame '%s'", goal_pose->pose.position.x,
379 goal_pose->pose.position.y, goal_pose->pose.position.z, goal_pose->header.frame_id.c_str());
380 auto_planning_timer_->cancel(); // cancel auto-planning timer until goal completion
381 has_active_waypoint_ = false;
383 this->sendGoal(goal_pose);
384 } else {
385 RCLCPP_ERROR(this->get_logger(), "Failed to generate random goal pose");
386 }
387}

◆ resultCallback()

void plan_route_action_client::PlanRouteActionClient::resultCallback ( const GoalHandlePlanRoute::WrappedResult & result)
private

Callback for result from the action server.

Parameters
[in]resultaction result

Definition at line 442 of file plan_route_action_client.cpp.

442 {
443 const double distance_traveled = result.result->distance_traveled;
444 const builtin_interfaces::msg::Duration& time_traveled = result.result->time_traveled;
445 const double wait_time_s = has_active_waypoint_ ? active_waypoint_wait_time_s_ : 0.0;
446
447 if (result.code == rclcpp_action::ResultCode::SUCCEEDED) {
448 if (result.result->destination_reached) {
449 RCLCPP_INFO(this->get_logger(), "Goal succeeded: destination reached after %.2fm and %ds", distance_traveled,
450 time_traveled.sec);
451 } else {
452 RCLCPP_WARN(this->get_logger(), "Goal succeeded, but destination not reached after %.2fm and %ds", distance_traveled,
453 time_traveled.sec);
454 }
455 } else if (result.code == rclcpp_action::ResultCode::CANCELED) {
456 RCLCPP_WARN(this->get_logger(), "Goal canceled: traveled %.2fm and %ds", distance_traveled, time_traveled.sec);
457 } else if (result.code == rclcpp_action::ResultCode::ABORTED) {
458 RCLCPP_ERROR(this->get_logger(), "Goal aborted: traveled %.2fm and %ds", distance_traveled, time_traveled.sec);
459 } else {
460 RCLCPP_ERROR(this->get_logger(), "Goal finished with unknown result code: %d", static_cast<int>(result.code));
461 }
462
463 has_active_waypoint_ = false;
465 if (result.code == rclcpp_action::ResultCode::SUCCEEDED && wait_time_s > 0.0) {
466 RCLCPP_INFO(this->get_logger(), "Waiting %.2fs before planning next waypoint", wait_time_s);
467 const double now_s = std::chrono::duration<double>(std::chrono::steady_clock::now().time_since_epoch()).count();
468 auto_planning_resume_time_s_ = now_s + wait_time_s;
469 }
470 auto_planning_timer_->reset(); // restart auto-planning timer
471}

◆ sendGoal()

void plan_route_action_client::PlanRouteActionClient::sendGoal ( const geometry_msgs::msg::PoseStamped::SharedPtr msg,
const std::vector< geometry_msgs::msg::PointStamped > & intermediate_destinations = {} )
private

Sends a goal to the action server.

Parameters
[in]msggoal pose
[in]intermediate_destinationsintermediate destinations to route via

Definition at line 389 of file plan_route_action_client.cpp.

390 {
391 RCLCPP_INFO(this->get_logger(), "Requesting to plan route to destination (%.3f, %.3f, %.3f) in frame '%s'",
392 msg->pose.position.x, msg->pose.position.y, msg->pose.position.z, msg->header.frame_id.c_str());
393
394 // check if action server is available
395 if (!action_client_->wait_for_action_server(std::chrono::duration<double>(0.1))) {
396 RCLCPP_ERROR(this->get_logger(), "Action server not available, aborting");
397 has_active_waypoint_ = false;
398 auto_planning_timer_->reset(); // restart auto-planning timer
399 return;
400 }
401
402 // build goal
403 auto goal = PlanRoute::Goal();
404 goal.destination = geometry_msgs::msg::PointStamped();
405 goal.destination.header = msg->header;
406 goal.destination.point = msg->pose.position;
407 goal.intermediate_destinations = intermediate_destinations;
408
409 // send goal
410 auto send_goal_options = rclcpp_action::Client<PlanRoute>::SendGoalOptions();
411 send_goal_options.goal_response_callback = std::bind(&PlanRouteActionClient::goalResponseCallback, this, std::placeholders::_1);
412 send_goal_options.feedback_callback =
413 std::bind(&PlanRouteActionClient::feedbackCallback, this, std::placeholders::_1, std::placeholders::_2);
414 send_goal_options.result_callback = std::bind(&PlanRouteActionClient::resultCallback, this, std::placeholders::_1);
415 goal_handle_future_ = action_client_->async_send_goal(goal, send_goal_options);
416 RCLCPP_INFO(this->get_logger(), "Goal sent");
417}
std::shared_future< GoalHandlePlanRoute::SharedPtr > goal_handle_future_
Goal handle.
void resultCallback(const GoalHandlePlanRoute::WrappedResult &result)
Callback for result from the action server.
void goalResponseCallback(const GoalHandlePlanRoute::SharedPtr &goal_handle)
Callback for goal response from the action server.
void feedbackCallback(GoalHandlePlanRoute::SharedPtr goal_handle, const std::shared_ptr< const PlanRoute::Feedback > feedback)
Callback for feedback from the action server.

◆ setup()

void plan_route_action_client::PlanRouteActionClient::setup ( )
private

Sets up subscribers, publishers, etc. to configure the node.

Definition at line 200 of file plan_route_action_client.cpp.

200 {
201 // callback for dynamic parameter configuration
203 this->add_on_set_parameters_callback(std::bind(&PlanRouteActionClient::parametersCallback, this, std::placeholders::_1));
204
205 // subscriber for goal pose
206 goal_pose_subscriber_ = this->create_subscription<geometry_msgs::msg::PoseStamped>(
207 "~/goal_pose", 10, std::bind(&PlanRouteActionClient::goalPoseCallback, this, std::placeholders::_1));
208 RCLCPP_INFO(this->get_logger(), "Subscribed to '%s'", goal_pose_subscriber_->get_topic_name());
209
210 // action client
211 action_client_ = rclcpp_action::create_client<PlanRoute>(this, "/planning/lanelet2_route_planning/plan_route");
212
213 // ll2 map interface
214 ll2_interface_ = std::make_unique<Lanelet2MapInterface>(*this, ll2_map_server_name_);
215
216 // parse waypoints
217 auto parsed_waypoints = parseWaypoints(waypoints_param_, waypoint_wait_times_, this->get_logger());
218 if (parsed_waypoints) {
219 waypoints_ = *parsed_waypoints;
220 } else {
221 std::stringstream ss;
222 ss << "Failed to parse parameter 'waypoints': [";
223 for (const auto& waypoint : waypoints_param_) {
224 ss << waypoint << (&waypoint != &waypoints_param_.back() ? ", " : "]");
225 }
226 RCLCPP_ERROR(this->get_logger(), "%s", ss.str().c_str());
227 }
228
229 // set up auto-planning timer
230 auto_planning_timer_ = this->create_wall_timer(std::chrono::milliseconds(1000),
232}
void goalPoseCallback(const geometry_msgs::msg::PoseStamped::SharedPtr msg)
Callback for goal pose (most likely received from RViz)
rcl_interfaces::msg::SetParametersResult parametersCallback(const std::vector< rclcpp::Parameter > &parameters)
Handles reconfiguration when a parameter value is changed.
void autoPlanningTimerCallback()
Callback for automatically planning a route, e.g., if waypoints are given.
OnSetParametersCallbackHandle::SharedPtr parameters_callback_
Callback handle for dynamic parameter reconfiguration.
rclcpp::Subscription< geometry_msgs::msg::PoseStamped >::SharedPtr goal_pose_subscriber_
Subscriber for goal pose.

Member Data Documentation

◆ action_client_

rclcpp_action::Client<PlanRoute>::SharedPtr plan_route_action_client::PlanRouteActionClient::action_client_
private

Action client.

Definition at line 157 of file plan_route_action_client.hpp.

◆ active_waypoint_wait_time_s_

double plan_route_action_client::PlanRouteActionClient::active_waypoint_wait_time_s_ = 0.0
private

Wait time of the active waypoint [s].

Definition at line 197 of file plan_route_action_client.hpp.

◆ auto_planning_resume_time_s_

double plan_route_action_client::PlanRouteActionClient::auto_planning_resume_time_s_ = 0.0
private

Earliest wall-clock time at which automatic planning may continue.

Definition at line 202 of file plan_route_action_client.hpp.

◆ auto_planning_timer_

rclcpp::TimerBase::SharedPtr plan_route_action_client::PlanRouteActionClient::auto_planning_timer_
private

Timer to automatically plan route, e.g., if waypoints are given.

Definition at line 167 of file plan_route_action_client.hpp.

◆ auto_reconfigurable_params_

std::vector<std::tuple<std::string, std::function<void(const rclcpp::Parameter&)> > > plan_route_action_client::PlanRouteActionClient::auto_reconfigurable_params_
private

Auto-reconfigurable parameters for dynamic reconfiguration.

Definition at line 142 of file plan_route_action_client.hpp.

◆ cancel_route_

bool plan_route_action_client::PlanRouteActionClient::cancel_route_ = false
private

Flag to cancel the route planning action (parameter)

Definition at line 236 of file plan_route_action_client.hpp.

◆ enable_continuous_planning_

bool plan_route_action_client::PlanRouteActionClient::enable_continuous_planning_ = false
private

Whether to continuously plan a new route (parameter)

Either to the next waypoint or to a random destination, if enabled

Definition at line 231 of file plan_route_action_client.hpp.

◆ enable_random_destination_

bool plan_route_action_client::PlanRouteActionClient::enable_random_destination_ = false
private

Whether to plan a route to a random destination (parameter)

Definition at line 224 of file plan_route_action_client.hpp.

◆ goal_handle_future_

std::shared_future<GoalHandlePlanRoute::SharedPtr> plan_route_action_client::PlanRouteActionClient::goal_handle_future_
private

Goal handle.

Definition at line 162 of file plan_route_action_client.hpp.

◆ goal_pose_subscriber_

rclcpp::Subscription<geometry_msgs::msg::PoseStamped>::SharedPtr plan_route_action_client::PlanRouteActionClient::goal_pose_subscriber_
private

Subscriber for goal pose.

Definition at line 152 of file plan_route_action_client.hpp.

◆ has_active_waypoint_

bool plan_route_action_client::PlanRouteActionClient::has_active_waypoint_ = false
private

Whether the active goal belongs to the waypoint list.

Definition at line 192 of file plan_route_action_client.hpp.

◆ has_completed_one_goal_

bool plan_route_action_client::PlanRouteActionClient::has_completed_one_goal_ = false
private

Whether one goal has been completed (succeeded or failed)

Definition at line 207 of file plan_route_action_client.hpp.

◆ ll2_interface_

std::unique_ptr<Lanelet2MapInterface> plan_route_action_client::PlanRouteActionClient::ll2_interface_
private

Lanelet2 map interface.

Definition at line 172 of file plan_route_action_client.hpp.

◆ ll2_map_server_name_

std::string plan_route_action_client::PlanRouteActionClient::ll2_map_server_name_ = "ll2_map_server"
private

Name of lanelet2_map_server node (parameter)

Definition at line 212 of file plan_route_action_client.hpp.

◆ next_waypoint_idx_

size_t plan_route_action_client::PlanRouteActionClient::next_waypoint_idx_ = 0
private

Index of next waypoint to follow.

Definition at line 187 of file plan_route_action_client.hpp.

◆ parameters_callback_

OnSetParametersCallbackHandle::SharedPtr plan_route_action_client::PlanRouteActionClient::parameters_callback_
private

Callback handle for dynamic parameter reconfiguration.

Definition at line 147 of file plan_route_action_client.hpp.

◆ waypoint_wait_times_

std::vector<double> plan_route_action_client::PlanRouteActionClient::waypoint_wait_times_
private

Wait time for each waypoint [s]; negative values mark intermediate destinations.

Definition at line 182 of file plan_route_action_client.hpp.

◆ waypoints_

std::vector<std::pair<double, double> > plan_route_action_client::PlanRouteActionClient::waypoints_
private

WGS84 waypoints to endlessly follow.

Definition at line 177 of file plan_route_action_client.hpp.

◆ waypoints_param_

std::vector<std::string> plan_route_action_client::PlanRouteActionClient::waypoints_param_
private

WGS84 waypoints to endlessly follow (parameter)

list of strings with comma-separated '<LATITUDE>,<LONGITUDE>[,<WAIT_TIME_S>]'

Definition at line 219 of file plan_route_action_client.hpp.


The documentation for this class was generated from the following files: