Carma-platform v4.2.0
CARMA Platform is built on robot operating system (ROS) and utilizes open source software (OSS) that enables Cooperative Driving Automation (CDA) features to allow Automated Driving Systems to interact and cooperate with infrastructure and other vehicles through communication.
route_following_plugin.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2022 LEIDOS.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
14 * the License.
15 */
16#include <rclcpp/rclcpp.hpp>
17#include <rclcpp/parameter_client.hpp>
18#include <string>
19#include <algorithm>
20#include <boost/uuid/uuid_generators.hpp>
21#include <boost/uuid/uuid_io.hpp>
23#include <lanelet2_core/geometry/Lanelet.h>
24#include <lanelet2_core/geometry/BoundingBox.h>
25#include <lanelet2_extension/traffic_rules/CarmaUSTrafficRules.h>
26#include <chrono>
27
29{
30 namespace std_ph = std::placeholders;
31
32namespace {
36double getManeuverEndSpeed(const carma_planning_msgs::msg::Maneuver& mvr) {
37 switch(mvr.type) {
38 case carma_planning_msgs::msg::Maneuver::LANE_FOLLOWING:
39 return mvr.lane_following_maneuver.end_speed;
40 case carma_planning_msgs::msg::Maneuver::LANE_CHANGE:
41 return mvr.lane_change_maneuver.end_speed;
42 case carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_STRAIGHT:
43 return mvr.intersection_transit_straight_maneuver.end_speed;
44 case carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_LEFT_TURN:
45 return mvr.intersection_transit_left_turn_maneuver.end_speed;
46 case carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_RIGHT_TURN:
47 return mvr.intersection_transit_right_turn_maneuver.end_speed;
48 case carma_planning_msgs::msg::Maneuver::STOP_AND_WAIT:
49 return 0;
50 default:
51 return 0;
52 }
53}
54
58void setManeuverLaneletIds(carma_planning_msgs::msg::Maneuver& mvr, lanelet::Id start_id, lanelet::Id end_id) {
59
60 switch(mvr.type) {
61 case carma_planning_msgs::msg::Maneuver::LANE_CHANGE:
62 mvr.lane_change_maneuver.starting_lane_id = std::to_string(start_id);
63 mvr.lane_change_maneuver.ending_lane_id = std::to_string(end_id);
64 break;
65 case carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_STRAIGHT:
66 mvr.intersection_transit_straight_maneuver.starting_lane_id = std::to_string(start_id);
67 mvr.intersection_transit_straight_maneuver.ending_lane_id = std::to_string(end_id);
68 break;
69 case carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_LEFT_TURN:
70 mvr.intersection_transit_left_turn_maneuver.starting_lane_id = std::to_string(start_id);
71 mvr.intersection_transit_left_turn_maneuver.ending_lane_id = std::to_string(end_id);
72 break;
73 case carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_RIGHT_TURN:
74 mvr.intersection_transit_right_turn_maneuver.starting_lane_id = std::to_string(start_id);
75 mvr.intersection_transit_right_turn_maneuver.ending_lane_id = std::to_string(end_id);
76 break;
77 case carma_planning_msgs::msg::Maneuver::STOP_AND_WAIT:
78 mvr.stop_and_wait_maneuver.starting_lane_id = std::to_string(start_id);
79 mvr.stop_and_wait_maneuver.ending_lane_id = std::to_string(end_id);
80 break;
81 default:
82 throw std::invalid_argument("Maneuver type does not have start,end lane ids");
83 }
84}
85
86}
87
88 RouteFollowingPlugin::RouteFollowingPlugin(const rclcpp::NodeOptions &options)
89 : carma_guidance_plugins::StrategicPlugin(options), tf2_buffer_(get_clock()), config_(Config())
90 {
91 // Declare parameters
92 config_.min_plan_duration_ = declare_parameter<double>("minimal_plan_duration", config_.min_plan_duration_);
93 config_.lane_change_plugin_= declare_parameter<std::string>("lane_change_plugin", config_.lane_change_plugin_);
94 config_.stop_and_wait_plugin_ = declare_parameter<std::string>("stop_and_wait_plugin", config_.stop_and_wait_plugin_);
95 config_.lanefollow_planning_tactical_plugin_ = declare_parameter<std::string>("lane_following_plugin", config_.lanefollow_planning_tactical_plugin_);
96 config_.route_end_point_buffer_ = declare_parameter<double>("guidance/route/destination_downtrack_range", config_.route_end_point_buffer_);
97 config_.accel_limit_ = declare_parameter<double>("vehicle_acceleration_limit", config_.accel_limit_);
98 config_.lateral_accel_limit_ = declare_parameter<double>("vehicle_lateral_accel_limit", config_.lateral_accel_limit_);
99 config_.stopping_accel_limit_multiplier_ = declare_parameter<double>("stopping_accel_limit_multiplier", config_.stopping_accel_limit_multiplier_);
100 config_.vehicle_id = declare_parameter<std::string>("vehicle_id", config_.vehicle_id);
101 config_.min_maneuver_length_ = declare_parameter<double>("min_maneuver_length", config_.min_maneuver_length_);
102 }
103
104 carma_ros2_utils::CallbackReturn RouteFollowingPlugin::on_configure_plugin()
105 {
106 config_ = Config();
107
108 get_parameter<double>("minimal_plan_duration", config_.min_plan_duration_);
109 get_parameter<std::string>("lane_change_plugin", config_.lane_change_plugin_);
110 get_parameter<std::string>("stop_and_wait_plugin", config_.stop_and_wait_plugin_);
111 get_parameter<std::string>("lane_following_plugin", config_.lanefollow_planning_tactical_plugin_);
112 get_parameter<double>("guidance/route/destination_downtrack_range", config_.route_end_point_buffer_);
113 get_parameter<double>("vehicle_acceleration_limit", config_.accel_limit_);
114 get_parameter<double>("vehicle_lateral_accel_limit", config_.lateral_accel_limit_);
115 get_parameter<double>("stopping_accel_limit_multiplier", config_.stopping_accel_limit_multiplier_);
116 get_parameter<double>("min_maneuver_length", config_.min_maneuver_length_);
117
118 RCLCPP_INFO_STREAM(rclcpp::get_logger("route_following_plugin"), "RouteFollowingPlugin Config: " << config_);
119
120 // Setup subscribers
121 twist_sub_ = create_subscription<geometry_msgs::msg::TwistStamped>("current_velocity", 50,
122 std::bind(&RouteFollowingPlugin::twist_cb,this,std_ph::_1));
123 current_maneuver_plan_sub_ = create_subscription<carma_planning_msgs::msg::ManeuverPlan>("maneuver_plan", 50,
124 std::bind(&RouteFollowingPlugin::current_maneuver_plan_cb,this,std_ph::_1));
125
126 // set world model point form wm listener
128
130
131 //set a route callback to update route and calculate maneuver
132 wml_->setRouteCallback([this]() {
133 RCLCPP_INFO_STREAM(get_logger(),"Recomputing maneuvers due to a route update");
134 this->latest_maneuver_plan_ = routeCb(wm_->getRoute()->shortestPath());
135 });
136
137 wml_->setMapCallback([this]() {
138 if (wm_->getRoute()) { // If this map update occured after a route was provided we need to regenerate maneuvers
139 RCLCPP_INFO_STREAM(get_logger(),"Recomputing maneuvers due to map update");
140 this->latest_maneuver_plan_ = routeCb(wm_->getRoute()->shortestPath());
141 }
142 });
143
145
146 // Return success if everthing initialized successfully
147 return CallbackReturn::SUCCESS;
148 }
149
150 carma_ros2_utils::CallbackReturn RouteFollowingPlugin::on_activate_plugin()
151 {
152 bumper_pose_timer_ = create_timer(get_clock(),
153 std::chrono::milliseconds(100),
154 std::bind(&RouteFollowingPlugin::bumper_pose_cb, this));
155
156 // Return success if everthing initialized successfully
157 return CallbackReturn::SUCCESS;
158 }
159
160 void RouteFollowingPlugin::twist_cb(geometry_msgs::msg::TwistStamped::UniquePtr msg)
161 {
162 current_speed_ = msg->twist.linear.x;
163 }
164
165 void RouteFollowingPlugin::current_maneuver_plan_cb(carma_planning_msgs::msg::ManeuverPlan::UniquePtr msg) {
166 current_maneuver_plan_ = std::move(msg);
167 }
168
169 std::vector<carma_planning_msgs::msg::Maneuver> RouteFollowingPlugin::routeCb(const lanelet::routing::LaneletPath &route_shortest_path)
170 {
171
172
173 for (const auto& ll:route_shortest_path)
174 {
175 shortest_path_set_.insert(ll.id());
176 }
177 std::vector<carma_planning_msgs::msg::Maneuver> maneuvers;
178 //This function calculates the maneuver plan every time the route is set
179 RCLCPP_DEBUG_STREAM(get_logger(),"New route created");
180
181 //Go through entire route - identify lane changes and fill in the spaces with lane following
182 auto nearest_lanelets = lanelet::geometry::findNearest(wm_->getMap()->laneletLayer, current_loc_, 10); //Return 10 nearest lanelets
183 if (nearest_lanelets.empty())
184 {
185 RCLCPP_WARN_STREAM(get_logger(),"Cannot find any lanelet in map!");
186
187 return maneuvers;
188 }
189
190 maneuvers.reserve(route_shortest_path.size());
191
192 double route_length = wm_->getRouteEndTrackPos().downtrack;
193 double start_dist = 0.0;
194 double end_dist = 0.0;
195 double start_speed = 0.0;
196
197 size_t shortest_path_index;
198 //Find lane changes in path - up to the second to last lanelet in path (till lane change is possible)
199 for (shortest_path_index = 0; shortest_path_index < route_shortest_path.size() - 1; ++shortest_path_index)
200 {
201 RCLCPP_DEBUG_STREAM(get_logger(),"current shortest_path_index:" << shortest_path_index);
202
203 auto following_lanelets = wm_->getRoute()->followingRelations(route_shortest_path[shortest_path_index]);
204 RCLCPP_DEBUG_STREAM(get_logger(),"following_lanelets.size():" << following_lanelets.size());
205
206 double target_speed_in_lanelet = findSpeedLimit(route_shortest_path[shortest_path_index]);
207
208 //update start distance and start speed from previous maneuver if it exists
209 start_dist = (maneuvers.empty()) ? wm_->routeTrackPos(route_shortest_path[shortest_path_index].centerline2d().front()).downtrack : GET_MANEUVER_PROPERTY(maneuvers.back(), end_dist); // TODO_REFAC if there is no initial maneuver start distance and start speed should be derived from current state. Current state ought to be provided in planning request
210 start_speed = (maneuvers.empty()) ? 0.0 : getManeuverEndSpeed(maneuvers.back());
211 RCLCPP_DEBUG_STREAM(get_logger(),"start_dist:" << start_dist << ", start_speed:" << start_speed);
212
213 end_dist = wm_->routeTrackPos(route_shortest_path[shortest_path_index].centerline2d().back()).downtrack;
214 RCLCPP_DEBUG_STREAM(get_logger(),"end_dist:" << end_dist);
215 end_dist = std::min(end_dist, route_length);
216 RCLCPP_DEBUG_STREAM(get_logger(),"min end_dist:" << end_dist);
217
218 if (std::fabs(start_dist - end_dist) < 0.1) //TODO: edge case that was not recreatable. Sometimes start and end dist was same which crashes inlanecruising
219 {
220 RCLCPP_WARN_STREAM(get_logger(),"start and end dist are equal! shortest path id" << shortest_path_index << ", lanelet id:" << route_shortest_path[shortest_path_index].id() <<
221 ", start and end dist:" << start_dist);
222 continue;
223 }
224
225
226
227 if (isLaneChangeNeeded(following_lanelets, route_shortest_path[shortest_path_index + 1].id()))
228 {
229 RCLCPP_DEBUG_STREAM(get_logger(),"LaneChangeNeeded");
230
231 // Determine the Lane Change Status
232 RCLCPP_DEBUG_STREAM(get_logger(),"Recording lanechange start_dist <<" << start_dist << ", from llt id:" << route_shortest_path[shortest_path_index].id() << " to llt id: " <<
233 route_shortest_path[shortest_path_index+ 1].id());
234
235 maneuvers.push_back(composeLaneChangeManeuverMessage(start_dist, end_dist, start_speed, target_speed_in_lanelet, route_shortest_path[shortest_path_index].id(), route_shortest_path[shortest_path_index + 1].id()));
236 ++shortest_path_index; //Since lane change covers 2 lanelets - skip planning for the next lanelet
237
238 }
239 else
240 {
241 RCLCPP_DEBUG_STREAM(get_logger(),"Lanechange NOT Needed ");
242 maneuvers.push_back(composeLaneFollowingManeuverMessage(start_dist, end_dist, start_speed, target_speed_in_lanelet, { route_shortest_path[shortest_path_index].id() } ));
243 }
244 }
245
246 // Add stop and wait maneuver as last maneuver if there is a lanelet unplanned for in path
247 if (shortest_path_index < route_shortest_path.size())
248 {
249
250 // Compute target deceleration for stopping
251 double stopping_accel_limit = config_.accel_limit_ * config_.stopping_accel_limit_multiplier_;
252
253 // Estimate the entry speed for the stopping maneuver
254 double stopping_entry_speed = maneuvers.empty() ? current_speed_ : getManeuverEndSpeed(maneuvers.back());
255
256 // Add stop and wait maneuver based on deceleration target and entry speed
257 maneuvers = addStopAndWaitAtRouteEnd( maneuvers, route_length, stopping_entry_speed, stopping_accel_limit, config_.lateral_accel_limit_, config_.min_maneuver_length_ );
258
259 }
261 RCLCPP_DEBUG_STREAM(get_logger(),"Maneuver plan along route successfully generated");
262 return maneuvers;
263 }
264
265 std::vector<carma_planning_msgs::msg::Maneuver> RouteFollowingPlugin::addStopAndWaitAtRouteEnd (
266 const std::vector<carma_planning_msgs::msg::Maneuver>& input_maneuvers,
267 double route_end_downtrack, double stopping_entry_speed, double stopping_logitudinal_accel,
268 double lateral_accel_limit, double min_maneuver_length
269 ) const
270 {
271 RCLCPP_INFO_STREAM(get_logger(),"Attempting to plan Stop and Wait Maneuver");
280 std::vector<carma_planning_msgs::msg::Maneuver> maneuvers = input_maneuvers; // Output maneuvers which will be modified
281
282
283 // Compute stopping distance where v_f = 0
284 // (v_f^2 - v_i^2) / (2*a) = d
285 double stopping_distance = 0.5 * (stopping_entry_speed * stopping_entry_speed) / stopping_logitudinal_accel;
286
287 // Compute required starting downtrack for maneuver
288 double required_start_downtrack = std::max(0.0, route_end_downtrack - stopping_distance);
289
290 // Loop to drop any maneuvers which fully overlap our stopping maneuver while accounting for minimum length maneuver buffers
291 while ( !maneuvers.empty() && maneuverWithBufferStartsAfterDowntrack(maneuvers.back(), required_start_downtrack, lateral_accel_limit, config_.min_maneuver_length_) ) {
292
293 RCLCPP_WARN_STREAM(get_logger(),"Dropping maneuver with id: " << GET_MANEUVER_PROPERTY(maneuvers.back(), parameters.maneuver_id) );
294
295 if (maneuvers.back().type == carma_planning_msgs::msg::Maneuver::LANE_CHANGE) {
296
297 // TODO develop more robust approach for this case per: https://github.com/usdot-fhwa-stol/carma-platform/issues/1350
298 throw std::invalid_argument("Stopping at the end of the route requires replanning a lane change. RouteFollowing cannot yet handle this case");
299 }
300
301 maneuvers.pop_back(); // Drop maneuver
302
303 }
304
305 double last_maneuver_end_downtrack = required_start_downtrack; // Set default starting location for stop and wait maneuver
306
307 if ( !maneuvers.empty() ) { // If there are existing maneuvers we need to make sure stop and wait does not overwrite them
308
309 last_maneuver_end_downtrack = GET_MANEUVER_PROPERTY(maneuvers.back(), end_dist);
310
311 // If our stopping maneuver does not intersect with existing maneuvers
312 if ( required_start_downtrack >= last_maneuver_end_downtrack ) {
313
314 // If the delta is under minimum_maneuver_length we can just extend the stopping maneuver
315 // Otherwise add a new lane follow maneuver
316 if (required_start_downtrack - last_maneuver_end_downtrack > min_maneuver_length) {
317
318 // Identify the lanelets which will be crossed by this lane follow maneuver
319 std::vector<lanelet::ConstLanelet> crossed_lanelets = wm_->getLaneletsBetween(last_maneuver_end_downtrack, required_start_downtrack, true, false);
320
321 if (crossed_lanelets.empty()) {
322 throw std::invalid_argument("The new lane follow maneuver does not cross any lanelets going from: " + std::to_string(last_maneuver_end_downtrack) + " to: " + std::to_string(required_start_downtrack));
323 }
324
325 // Create the lane follow maneuver
326 maneuvers.push_back(composeLaneFollowingManeuverMessage(last_maneuver_end_downtrack, required_start_downtrack, stopping_entry_speed, stopping_entry_speed, lanelet::utils::transform(crossed_lanelets, [](auto ll) { return ll.id(); })));
327
328 // Update last maneuver end downtrack so the stop and wait maneuver can be properly formulated
329 last_maneuver_end_downtrack = required_start_downtrack;
330 } else {
331 RCLCPP_DEBUG_STREAM(get_logger(),"Stop and wait maneuver being extended to nearest maneuver which is closer than the minimum maneuver length");
332 }
333
334 } else { // If our stopping maneuver intersects with existing maneuvers
335
336
337 SET_MANEUVER_PROPERTY(maneuvers.back(), end_dist, required_start_downtrack);
338
339 // Identify the lanelets which will be crossed by this updated maneuver
340 std::vector<lanelet::ConstLanelet> crossed_lanelets = wm_->getLaneletsBetween(GET_MANEUVER_PROPERTY(maneuvers.back(), start_dist), required_start_downtrack, true, false);
341
342 if (crossed_lanelets.empty()) {
343 throw std::invalid_argument("Updated maneuver does not cross any lanelets going from: " + std::to_string(GET_MANEUVER_PROPERTY(maneuvers.back(), start_dist)) + " to: " + std::to_string(required_start_downtrack));
344 }
345
346 // Set the impact lane ids for maneuvers
347 if (maneuvers.back().type == carma_planning_msgs::msg::Maneuver::LANE_FOLLOWING) {
348
349 maneuvers.back().lane_following_maneuver.lane_ids = lanelet::utils::transform(crossed_lanelets, [](auto ll) { return std::to_string(ll.id()); });
350
351 } else {
352
353 setManeuverLaneletIds(maneuvers.back(), crossed_lanelets.front().id(), crossed_lanelets.back().id());
354
355 }
356
357 last_maneuver_end_downtrack = required_start_downtrack;
358
359 }
360 }
361
362 // Identify the lanelets which will be crossed by this stop and wait maneuver
363 std::vector<lanelet::ConstLanelet> crossed_lanelets = wm_->getLaneletsBetween(last_maneuver_end_downtrack, route_end_downtrack, true, false);
364
365 if (crossed_lanelets.empty()) {
366
367 throw std::invalid_argument("Stopping maneuver does not cross any lanelets going from: " + std::to_string(last_maneuver_end_downtrack) + " to: " + std::to_string(route_end_downtrack));
368
369 }
370
371 lanelet::Id start_lane = crossed_lanelets.front().id();
372 lanelet::Id end_lane = crossed_lanelets.back().id();
373
374 // Build stop and wait maneuver
375 maneuvers.push_back(composeStopAndWaitManeuverMessage(last_maneuver_end_downtrack, route_end_downtrack, stopping_entry_speed, start_lane, end_lane,stopping_logitudinal_accel));
376
377 return maneuvers;
378
379 }
380
381 bool RouteFollowingPlugin::maneuverWithBufferStartsAfterDowntrack(const carma_planning_msgs::msg::Maneuver& maneuver, double downtrack, double lateral_accel, double min_maneuver_length) const {
382
383 if (maneuver.type == carma_planning_msgs::msg::Maneuver::LANE_CHANGE) {
384
385 // Compute the time it takes to move laterally to the next lane
386 double lane_change_time = sqrt(0.5 * MAX_LANE_WIDTH / lateral_accel);
387
388 // Compute logitudinal distance covered in lane change time
389 double min_lane_change_distance = std::max(
390 min_maneuver_length,
391 lane_change_time * (GET_MANEUVER_PROPERTY(maneuver, start_speed) + getManeuverEndSpeed(maneuver)) / 2.0 // dist = v_avg * t
392 );
393
394 return GET_MANEUVER_PROPERTY(maneuver, start_dist) + min_lane_change_distance > downtrack;
395
396 } else {
397
398 return GET_MANEUVER_PROPERTY(maneuver, start_dist) + min_maneuver_length > downtrack;
399
400 }
401 }
402
404 {
405 return true;
406 }
407
409 {
410 return "v1.0";
411 }
412
414 std::shared_ptr<rmw_request_id_t> srv_header,
415 carma_planning_msgs::srv::PlanManeuvers::Request::SharedPtr req,
416 carma_planning_msgs::srv::PlanManeuvers::Response::SharedPtr resp)
417 {
418
419 if (latest_maneuver_plan_.empty())
420 {
421 RCLCPP_ERROR_STREAM(get_logger(),"A maneuver plan has not been generated");
422 return;
423 }
424
425 double current_downtrack;
426
427 if (!req->prior_plan.maneuvers.empty())
428 {
429 current_downtrack = GET_MANEUVER_PROPERTY(req->prior_plan.maneuvers.back(), end_dist);
430 RCLCPP_DEBUG_STREAM(get_logger(),"Detected a prior plan! Using back maneuver's end_dist:"<< current_downtrack);
431 }
432 else
433 {
434 current_downtrack = req->veh_downtrack;
435 RCLCPP_DEBUG_STREAM(get_logger(),"Detected NO prior plan! Using req.veh_downtrack: "<< current_downtrack);
436 }
437
438 //Return the set of maneuvers which intersect with min_plan_duration
439 size_t i = 0;
440 double planned_time = 0.0;
441
442 std::vector<carma_planning_msgs::msg::Maneuver> new_maneuvers;
443
444 while (planned_time < config_.min_plan_duration_ && i < latest_maneuver_plan_.size())
445 {
446 RCLCPP_DEBUG_STREAM(get_logger(),"Checking maneuver id " << i);
447 //Ignore plans for distance already covered
448 if (GET_MANEUVER_PROPERTY(latest_maneuver_plan_[i], end_dist) <= current_downtrack)
449 {
450 RCLCPP_DEBUG_STREAM(get_logger(),"Skipping maneuver id " << i);
451
452 ++i;
453 continue;
454 }
455 if(planned_time == 0.0){
456 //update start distance of first maneuver
457 setManeuverStartDist(latest_maneuver_plan_[i], current_downtrack);
458 }
459 planned_time += getManeuverDuration(latest_maneuver_plan_[i], epsilon_).seconds();
460
461 new_maneuvers.push_back(latest_maneuver_plan_[i]);
462 ++i;
463 }
464
465 if (new_maneuvers.empty())
466 {
467 RCLCPP_WARN_STREAM(get_logger(),"Cannot plan maneuver because no route is found");
468 return;
469 }
470
471 //Update time progress for maneuvers
472 if (!req->prior_plan.maneuvers.empty())
473 {
474 updateTimeProgress(new_maneuvers, GET_MANEUVER_PROPERTY(req->prior_plan.maneuvers.back(), end_time));
475 RCLCPP_DEBUG_STREAM(get_logger(),"Detected a prior plan! Using back maneuver's end time:"<< std::to_string(rclcpp::Time(GET_MANEUVER_PROPERTY(req->prior_plan.maneuvers.back(), end_time)).seconds()));
476 RCLCPP_DEBUG_STREAM(get_logger(),"Where plan_completion_time was:"<< std::to_string(rclcpp::Time(req->prior_plan.planning_completion_time).seconds()));
477 }
478 else
479 {
480 updateTimeProgress(new_maneuvers, rclcpp::Time(req->header.stamp));
481 RCLCPP_DEBUG_STREAM(get_logger(),"Detected NO prior plan! Using this->now():"<< std::to_string(this->now().seconds()));
482 }
483
484 //update starting speed of first maneuver
485 if (!req->prior_plan.maneuvers.empty())
486 {
487 double start_speed;
488 switch (req->prior_plan.maneuvers.back().type)
489 {
490 case carma_planning_msgs::msg::Maneuver::LANE_FOLLOWING:
491 start_speed = req->prior_plan.maneuvers.back().lane_following_maneuver.end_speed;
492 break;
493 case carma_planning_msgs::msg::Maneuver::LANE_CHANGE:
494 start_speed = req->prior_plan.maneuvers.back().lane_change_maneuver.end_speed;
495 break;
496 case carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_STRAIGHT:
497 start_speed = req->prior_plan.maneuvers.back().intersection_transit_straight_maneuver.end_speed;
498 break;
499 case carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_LEFT_TURN:
500 start_speed = req->prior_plan.maneuvers.back().intersection_transit_left_turn_maneuver.end_speed;
501 break;
502 case carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_RIGHT_TURN:
503 start_speed = req->prior_plan.maneuvers.back().intersection_transit_right_turn_maneuver.end_speed;
504 break;
505 default:
506 throw std::invalid_argument("Invalid maneuver type, cannot update starting speed for maneuver");
507 }
508
509 updateStartingSpeed(new_maneuvers.front(), start_speed);
510 RCLCPP_DEBUG_STREAM(get_logger(),"Detected a prior plan! Using back maneuver's end speed:"<< start_speed);
511 }
512 else
513 {
514 updateStartingSpeed(new_maneuvers.front(), req->veh_logitudinal_velocity);
515 RCLCPP_DEBUG_STREAM(get_logger(),"Detected NO prior plan! Using req->veh_logitudinal_velocity:"<< req->veh_logitudinal_velocity);
516 }
517 //update plan
518 resp->new_plan = req->prior_plan;
519 RCLCPP_DEBUG_STREAM(get_logger(),"Updating maneuvers before returning... Prior plan size:" << req->prior_plan.maneuvers.size());
520 for (const auto& mvr : new_maneuvers)
521 {
522 resp->new_plan.maneuvers.push_back(mvr);
523 }
524
525 RCLCPP_DEBUG_STREAM(get_logger(),"Returning total of maneuver size: " << resp->new_plan.maneuvers.size());
526 resp->new_plan.planning_completion_time = this->now();
527
528 return;
529 }
530
532 {
533 RCLCPP_DEBUG_STREAM(get_logger(),"Entering pose_cb");
534
535 RCLCPP_DEBUG_STREAM(get_logger(),"Looking up front bumper pose...");
536
537 try
538 {
539 tf_ = tf2_buffer_.lookupTransform("map", "vehicle_front", rclcpp::Time(0), rclcpp::Duration(1, 0)); //save to local copy of transform 1 sec timeout
540 tf2::fromMsg(tf_, frontbumper_transform_);
541 }
542 catch (const tf2::TransformException &ex)
543 {
544 RCLCPP_WARN_STREAM(get_logger(),std::string(ex.what()));
545 }
546
547 geometry_msgs::msg::Pose front_bumper_pose;
548 front_bumper_pose.position.x = frontbumper_transform_.getOrigin().getX();
549 front_bumper_pose.position.y = frontbumper_transform_.getOrigin().getY();
550
551 if (!wm_->getRoute())
552 return;
553
554 lanelet::BasicPoint2d current_loc(front_bumper_pose.position.x, front_bumper_pose.position.y);
555 current_loc_ = current_loc;
556 double current_progress = wm_->routeTrackPos(current_loc).downtrack;
557
558 RCLCPP_DEBUG_STREAM(get_logger(),"pose_cb : current_progress" << current_progress);
559
560 // Check if we need to return to route shortest path.
561 // Step 1. Check if another plugin aside from RFP has been in control
562 if (current_maneuver_plan_ != nullptr &&
563 GET_MANEUVER_PROPERTY(current_maneuver_plan_->maneuvers[0], parameters.planning_strategic_plugin) \
565 // If another plugin may have brought us off shortest path, check our current lanelet
566 auto llts = wm_->getLaneletsFromPoint(current_loc, 10);
567 // Remove any candidate lanelets not on the route
568 llts.erase(std::remove_if(llts.begin(), llts.end(),
569 [&](auto lanelet) -> bool { return !wm_->getRoute()->contains(lanelet); }),
570 llts.end());
571
572 // !!! ASSUMPTION !!!:
573 // Once non-route lanelets have been removed, it is assumed that our actual current lanelet is the only one that can remain.
574 // TODO: Verify that this assumption is true in all cases OR implement more robust logic to track current lanelet when there are overlaps
575
576 if (llts.size() > 1) {
577 // Assumed that:
578 // 1. Vehicle is in a lanelet on the route.
579 // 2. The route does not contain overlapping lanelets.
580 RCLCPP_WARN_STREAM(get_logger(),"ANOMALOUS SIZE DETECTED FOR CURRENT LANELET CANDIDATES! SIZE: " << llts.size());
581 } else if (llts.size() < 1) {
582 // We've left the route entirely.
583 RCLCPP_ERROR_STREAM(get_logger(),"Vehicle has left the route entirely. Unable to compute new shortest path.");
584 throw std::domain_error("Vehicle not on route, unable to compute shortest path.");
585 }
586
587 const auto& current_lanelet = llts[0];
588 RCLCPP_DEBUG_STREAM(get_logger(), "Vehicle is currently in lanelet " << current_lanelet.id());
589
590 // if the current lanelet is not on the shortest path
591 if (shortest_path_set_.find(current_lanelet.id()) == shortest_path_set_.end())
592 {
593 RCLCPP_DEBUG_STREAM(get_logger(), "Generating a new shortest path since the vehicle is not on the shortest path");
594 returnToShortestPath(current_lanelet);
595 }
596
597 // Replan if vehicle currently located in a lane change planned by route_following_plugin, since a lane change maneuver can't begin part way through
598 for(size_t i = 0; i < latest_maneuver_plan_.size(); ++i){
599 if((GET_MANEUVER_PROPERTY(latest_maneuver_plan_[i], start_dist) <= current_progress) && (current_progress <= GET_MANEUVER_PROPERTY(latest_maneuver_plan_[i], end_dist))){
600 if(latest_maneuver_plan_[i].type == carma_planning_msgs::msg::Maneuver::LANE_CHANGE){
601 RCLCPP_DEBUG_STREAM(get_logger(), "Generating a new shortest path since vehicle is positioned in a lane change but the previous maneuver plan was not generated by route_following_plugin");
602 returnToShortestPath(current_lanelet);
603 }
604 }
605 }
606 }
607 }
608
609 rclcpp::Duration RouteFollowingPlugin::getManeuverDuration(carma_planning_msgs::msg::Maneuver &maneuver, double epsilon) const
610 {
611 double maneuver_start_speed = GET_MANEUVER_PROPERTY(maneuver, start_speed);
612 double manever_end_speed = getManeuverEndSpeed(maneuver);
613 double cur_plus_target = maneuver_start_speed + manever_end_speed;
614 if(cur_plus_target < epsilon){
615 throw std::invalid_argument("Maneuver start and ending speed is zero");
616 }
617 rclcpp::Duration duration{0,0};
618 double maneuver_start_dist = GET_MANEUVER_PROPERTY(maneuver, start_dist);
619 double maneuver_end_dist = GET_MANEUVER_PROPERTY(maneuver, end_dist);
620
621 RCLCPP_DEBUG_STREAM(get_logger(),"maneuver_end_dist: " << maneuver_end_dist << ", maneuver_start_dist: " << maneuver_start_dist << ", cur_plus_target: " << cur_plus_target);
622
623 duration = rclcpp::Duration((maneuver_end_dist - maneuver_start_dist) / (0.5 * cur_plus_target) * 1e9);
624
625 return duration;
626 }
627
628 void RouteFollowingPlugin::updateTimeProgress(std::vector<carma_planning_msgs::msg::Maneuver> &maneuvers, rclcpp::Time start_time) const
629 {
630 rclcpp::Time time_progress = start_time;
631 rclcpp::Time prev_time = time_progress;
632
633 for (auto &maneuver : maneuvers)
634 {
635 time_progress += getManeuverDuration(maneuver, epsilon_);
636 switch (maneuver.type)
637 {
638 case carma_planning_msgs::msg::Maneuver::LANE_FOLLOWING:
639 maneuver.lane_following_maneuver.start_time = prev_time;
640 maneuver.lane_following_maneuver.end_time = time_progress;
641 break;
642 case carma_planning_msgs::msg::Maneuver::LANE_CHANGE:
643 maneuver.lane_change_maneuver.start_time = prev_time;
644 maneuver.lane_change_maneuver.end_time = time_progress;
645 break;
646 case carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_STRAIGHT:
647 maneuver.intersection_transit_straight_maneuver.start_time = prev_time;
648 maneuver.intersection_transit_straight_maneuver.end_time = time_progress;
649 break;
650 case carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_LEFT_TURN:
651 maneuver.intersection_transit_left_turn_maneuver.start_time = prev_time;
652 maneuver.intersection_transit_left_turn_maneuver.end_time = time_progress;
653 break;
654 case carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_RIGHT_TURN:
655 maneuver.intersection_transit_right_turn_maneuver.start_time = prev_time;
656 maneuver.intersection_transit_right_turn_maneuver.end_time = time_progress;
657 break;
658 case carma_planning_msgs::msg::Maneuver::STOP_AND_WAIT:
659 maneuver.stop_and_wait_maneuver.start_time = prev_time;
660 maneuver.stop_and_wait_maneuver.start_time = time_progress;
661 maneuver.stop_and_wait_maneuver.end_time = start_time + rclcpp::Duration(86400, 0); // Set maneuver time period as 24hrs since this is the end of the route
662 break;
663 default:
664 throw std::invalid_argument("Invalid maneuver type, cannot update time progress for maneuver");
665 }
666 prev_time = time_progress;
667 }
668 }
669
670 void RouteFollowingPlugin::updateStartingSpeed(carma_planning_msgs::msg::Maneuver &maneuver, double start_speed) const
671 {
672 switch (maneuver.type)
673 {
674 case carma_planning_msgs::msg::Maneuver::LANE_FOLLOWING:
675 maneuver.lane_following_maneuver.start_speed = start_speed;
676 break;
677 case carma_planning_msgs::msg::Maneuver::LANE_CHANGE:
678 maneuver.lane_change_maneuver.start_speed = start_speed;
679 break;
680 case carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_STRAIGHT:
681 maneuver.intersection_transit_straight_maneuver.start_speed = start_speed;
682 break;
683 case carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_LEFT_TURN:
684 maneuver.intersection_transit_left_turn_maneuver.start_speed = start_speed;
685 break;
686 case carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_RIGHT_TURN:
687 maneuver.intersection_transit_right_turn_maneuver.start_speed = start_speed;
688 break;
689 case carma_planning_msgs::msg::Maneuver::STOP_AND_WAIT:
690 maneuver.stop_and_wait_maneuver.start_speed = start_speed;
691 break;
692 default:
693 throw std::invalid_argument("Invalid maneuver type, cannot update starting speed for maneuver");
694 }
695 }
696
697 void RouteFollowingPlugin::setManeuverStartDist(carma_planning_msgs::msg::Maneuver &maneuver, double start_dist) const
698 {
699 switch (maneuver.type)
700 {
701 case carma_planning_msgs::msg::Maneuver::LANE_FOLLOWING:
702 maneuver.lane_following_maneuver.start_dist = start_dist;
703 break;
704 case carma_planning_msgs::msg::Maneuver::LANE_CHANGE:
705 maneuver.lane_change_maneuver.start_dist = start_dist;
706 break;
707 case carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_STRAIGHT:
708 maneuver.intersection_transit_straight_maneuver.start_dist = start_dist;
709 break;
710 case carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_LEFT_TURN:
711 maneuver.intersection_transit_left_turn_maneuver.start_dist = start_dist;
712 break;
713 case carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_RIGHT_TURN:
714 maneuver.intersection_transit_right_turn_maneuver.start_dist = start_dist;
715 break;
716 case carma_planning_msgs::msg::Maneuver::STOP_AND_WAIT:
717 maneuver.stop_and_wait_maneuver.start_dist = start_dist;
718 break;
719 default:
720 throw std::invalid_argument("Invalid maneuver type");
721 }
722 }
723
724 carma_planning_msgs::msg::Maneuver RouteFollowingPlugin::composeLaneFollowingManeuverMessage(double start_dist, double end_dist, double start_speed, double target_speed, const std::vector<lanelet::Id>& lane_ids) const
725 {
726 carma_planning_msgs::msg::Maneuver maneuver_msg;
727 maneuver_msg.type = carma_planning_msgs::msg::Maneuver::LANE_FOLLOWING;
728 maneuver_msg.lane_following_maneuver.parameters.negotiation_type = carma_planning_msgs::msg::ManeuverParameters::NO_NEGOTIATION;
729 maneuver_msg.lane_following_maneuver.parameters.presence_vector = carma_planning_msgs::msg::ManeuverParameters::HAS_TACTICAL_PLUGIN;
730 maneuver_msg.lane_following_maneuver.parameters.planning_tactical_plugin = lanefollow_planning_tactical_plugin_;
731 maneuver_msg.lane_following_maneuver.parameters.planning_strategic_plugin = planning_strategic_plugin_;
732 maneuver_msg.lane_following_maneuver.start_dist = start_dist;
733 maneuver_msg.lane_following_maneuver.start_speed = start_speed;
734 maneuver_msg.lane_following_maneuver.end_dist = end_dist;
735 maneuver_msg.lane_following_maneuver.end_speed = target_speed;
736 maneuver_msg.lane_following_maneuver.lane_ids = lanelet::utils::transform(lane_ids, [](auto id) { return std::to_string(id); });
737 //Start time and end time for maneuver are assigned in updateTimeProgress
738
739 // NOTE: The maneuver id is set here because maneuvers are regenerated once per route, so it is acceptable to regenerate them on route updates.
740 // If maneuvers were not generated only on route updates we would want to preserve the ids across plans
741 maneuver_msg.lane_following_maneuver.parameters.maneuver_id = getNewManeuverId();
742
743 std::stringstream ss;
744 for (const auto& id : maneuver_msg.lane_following_maneuver.lane_ids)
745 ss << " " << id;
746
747 RCLCPP_DEBUG_STREAM(get_logger(),"Creating lane follow id: " << maneuver_msg.lane_following_maneuver.parameters.maneuver_id
748 << " start dist: " << start_dist << " end dist: " << end_dist << "lane_ids: " << ss.str());
749
750 return maneuver_msg;
751 }
752
753 carma_planning_msgs::msg::Maneuver RouteFollowingPlugin::composeLaneChangeManeuverMessage(double start_dist, double end_dist, double start_speed, double target_speed, lanelet::Id starting_lane_id, lanelet::Id ending_lane_id) const
754 {
755 carma_planning_msgs::msg::Maneuver maneuver_msg;
756 maneuver_msg.type = carma_planning_msgs::msg::Maneuver::LANE_CHANGE;
757 maneuver_msg.lane_change_maneuver.parameters.negotiation_type = carma_planning_msgs::msg::ManeuverParameters::NO_NEGOTIATION;
758 maneuver_msg.lane_change_maneuver.parameters.presence_vector = carma_planning_msgs::msg::ManeuverParameters::HAS_TACTICAL_PLUGIN;
759 maneuver_msg.lane_change_maneuver.parameters.planning_tactical_plugin = lane_change_plugin_;
760 maneuver_msg.lane_change_maneuver.parameters.planning_strategic_plugin = planning_strategic_plugin_;
761 maneuver_msg.lane_change_maneuver.start_dist = start_dist;
762 maneuver_msg.lane_change_maneuver.start_speed = start_speed;
763 maneuver_msg.lane_change_maneuver.end_dist = end_dist;
764 maneuver_msg.lane_change_maneuver.end_speed = target_speed;
765 maneuver_msg.lane_change_maneuver.starting_lane_id = std::to_string(starting_lane_id);
766 maneuver_msg.lane_change_maneuver.ending_lane_id = std::to_string(ending_lane_id);
767 //Start time and end time for maneuver are assigned in updateTimeProgress
768
769 // NOTE: The maneuver id is set here because maneuvers are regenerated once per route, so it is acceptable to regenerate them on route updates.
770 // If maneuvers were not generated only on route updates we would want to preserve the ids across plans
771 maneuver_msg.lane_change_maneuver.parameters.maneuver_id = getNewManeuverId();
772
773 RCLCPP_DEBUG_STREAM(get_logger(),"Creating lane change id: " << maneuver_msg.lane_change_maneuver.parameters.maneuver_id << "start dist: " << start_dist << " end dist: " << end_dist << " Starting llt: " << starting_lane_id << " Ending llt: " << ending_lane_id);
774
775 return maneuver_msg;
776 }
777
779 static auto gen = boost::uuids::random_generator(); // Initialize uuid generator
780
781 return boost::lexical_cast<std::string>(gen()); // generate uuid and convert to string
782 }
783
784 carma_planning_msgs::msg::Maneuver RouteFollowingPlugin::composeStopAndWaitManeuverMessage(double start_dist, double end_dist, double start_speed, lanelet::Id starting_lane_id, lanelet::Id ending_lane_id, double stopping_accel) const
785 {
786 carma_planning_msgs::msg::Maneuver maneuver_msg;
787 maneuver_msg.type = carma_planning_msgs::msg::Maneuver::STOP_AND_WAIT;
788 maneuver_msg.stop_and_wait_maneuver.parameters.negotiation_type = carma_planning_msgs::msg::ManeuverParameters::NO_NEGOTIATION;
789 maneuver_msg.stop_and_wait_maneuver.parameters.presence_vector = carma_planning_msgs::msg::ManeuverParameters::HAS_TACTICAL_PLUGIN
790 | carma_planning_msgs::msg::ManeuverParameters::HAS_FLOAT_META_DATA;
791 maneuver_msg.stop_and_wait_maneuver.parameters.planning_tactical_plugin = stop_and_wait_plugin_;
792 maneuver_msg.stop_and_wait_maneuver.parameters.planning_strategic_plugin = planning_strategic_plugin_;
793 maneuver_msg.stop_and_wait_maneuver.start_dist = start_dist;
794 maneuver_msg.stop_and_wait_maneuver.start_speed = start_speed;
795 maneuver_msg.stop_and_wait_maneuver.end_dist = end_dist;
796 maneuver_msg.stop_and_wait_maneuver.starting_lane_id = std::to_string(starting_lane_id);
797 maneuver_msg.stop_and_wait_maneuver.ending_lane_id = std::to_string(ending_lane_id);
798 //Start time and end time for maneuver are assigned in updateTimeProgress
799
800 // Set the meta-data for the StopAndWait Maneuver to define the buffer in the route end point stopping location
801 maneuver_msg.stop_and_wait_maneuver.parameters.float_valued_meta_data.push_back(config_.route_end_point_buffer_);
802 maneuver_msg.stop_and_wait_maneuver.parameters.float_valued_meta_data.push_back(stopping_accel);
803
804 // NOTE: The maneuver id is set here because maneuvers are regenerated once per route, so it is acceptable to regenerate them on route updates.
805 // If maneuvers were not generated only on route updates we would want to preserve the ids across plans
806 maneuver_msg.stop_and_wait_maneuver.parameters.maneuver_id = getNewManeuverId();
807
808 RCLCPP_DEBUG_STREAM(get_logger(),"Creating stop and wait maneuver id:" << maneuver_msg.stop_and_wait_maneuver.parameters.maneuver_id << "start dist: " << start_dist << " end dist: " << end_dist << " start_speed: " << start_speed << " Starting llt: " << starting_lane_id << " Ending llt: " << ending_lane_id);
809
810 return maneuver_msg;
811 }
812
813 bool RouteFollowingPlugin::isLaneChangeNeeded(lanelet::routing::LaneletRelations relations, lanelet::Id target_id) const
814 {
815 //This method is constrained to the lanelet being checked against being accessible. A non-accessible target lanelet would result in unspecified behavior
816 for (auto &relation : relations)
817 {
818 if (relation.lanelet.id() == target_id && relation.relationType == lanelet::routing::RelationType::Successor)
819 {
820 return false;
821 }
822 }
823 return true;
824 }
825
826 double RouteFollowingPlugin::findSpeedLimit(const lanelet::ConstLanelet &llt)
827 {
828 lanelet::Optional<carma_wm::TrafficRulesConstPtr> traffic_rules = wm_->getTrafficRules();
829 if (traffic_rules)
830 {
831 return (*traffic_rules)->speedLimit(llt).speedLimit.value();
832 }
833 else
834 {
835 throw std::invalid_argument("Valid traffic rules object could not be built");
836 }
837 }
838
840 {
841 tf2_listener_.reset(new tf2_ros::TransformListener(tf2_buffer_));
842 tf2_buffer_.setUsingDedicatedThread(true);
843 }
844
845 void RouteFollowingPlugin::returnToShortestPath(const lanelet::ConstLanelet &current_lanelet)
846 {
847 auto original_shortestpath = wm_->getRoute()->shortestPath();
848 RCLCPP_DEBUG_STREAM(get_logger(),"The vehicle has left the shortest path");
849 auto routing_graph = wm_->getMapRoutingGraph();
850
851 // Obtain the lanelet following the current lanelet in this same lane, this lanelet must exist since the new shortest path cannot begin with a lane change
852 auto current_lane_following_lanelets = routing_graph->following(current_lanelet);
853 lanelet::ConstLanelet current_lane_following_lanelet;
854 if(!current_lane_following_lanelets.empty()){
855 current_lane_following_lanelet = current_lane_following_lanelets[0];
856 }
857 else{
858 throw std::invalid_argument("The current lanelet does not have a following lanelet. Vehicle cannot return to shortest path!");
859 }
860
861 // In order to return to the shortest path, the closest future lanelet on the shortest path needs to be found.
862 // That is the adjacent lanelet of the following lanelet of the current lanelet.
863 auto adjacent_lanelets = routing_graph->besides(current_lane_following_lanelet);
864 if (!adjacent_lanelets.empty())
865 {
866 for (const auto& adjacent:adjacent_lanelets)
867 {
868 if (shortest_path_set_.find(adjacent.id())!=shortest_path_set_.end())
869 {
870 auto following_lanelets = routing_graph->following(adjacent);
871 const auto& target_following_lanelet = following_lanelets[0];
872 RCLCPP_DEBUG_STREAM(get_logger(),"The target_following_lanelet id is: " << target_following_lanelet.id());
873 lanelet::ConstLanelets interm;
874 interm.push_back(static_cast<lanelet::ConstLanelet>(current_lane_following_lanelet));
875 interm.push_back(static_cast<lanelet::ConstLanelet>(target_following_lanelet));
876 // a new shortest path, via the the lanelets in 'interm' is calculated and used an alternative shortest path
877 auto new_shortestpath = routing_graph->shortestPathVia(current_lanelet, interm, original_shortestpath.back());
878 RCLCPP_DEBUG_STREAM(get_logger(),"a new shortestpath is generated to return to original shortestpath");
879 // routeCb is called to update latest_maneuver_plan_
880 if (new_shortestpath) this->latest_maneuver_plan_ = routeCb(new_shortestpath.get());
881 break;
882 }
883 else
884 {
885 // a new shortest path, via the current_lanelet is calculated and used an alternative shortest path
886 lanelet::ConstLanelets new_interm;
887 new_interm.push_back(static_cast<lanelet::ConstLanelet>(current_lane_following_lanelet));
888 auto new_shortestpath = routing_graph->shortestPathVia(current_lanelet, new_interm, original_shortestpath.back());
889 RCLCPP_DEBUG_STREAM(get_logger(),"Cannot return to the original shortestpath from adjacent lanes, so a new shortestpath is generated");
890 // routeCb is called to update latest_maneuver_plan_
891 if (new_shortestpath) this->latest_maneuver_plan_ = routeCb(new_shortestpath.get());
892 }
893 }
894
895 }
896 else
897 {
898 RCLCPP_WARN_STREAM(get_logger(),"Alternative shortest path cannot be generated");
899 }
900
901 }
902
903}
904
905#include "rclcpp_components/register_node_macro.hpp"
906
907// Register the component with class_loader
908RCLCPP_COMPONENTS_REGISTER_NODE(route_following_plugin::RouteFollowingPlugin)
#define GET_MANEUVER_PROPERTY(mvr, property)
Macro definition to enable easier access to fields shared across the maneuver types.
virtual carma_wm::WorldModelConstPtr get_world_model() final
Method to return the default world model provided as a convience by this base class If this method or...
virtual std::shared_ptr< carma_wm::WMListener > get_world_model_listener() final
Method to return the default world model listener provided as a convience by this base class If this ...
carma_ros2_utils::CallbackReturn on_configure_plugin()
Method which is triggered when this plugin is moved from the UNCONFIGURED to INACTIVE states....
std::string get_version_id()
Returns the version id of this plugin.
void initializeBumperTransformLookup()
Initialize transform lookup from front bumper to map.
std::vector< carma_planning_msgs::msg::Maneuver > latest_maneuver_plan_
std::unordered_set< lanelet::Id > shortest_path_set_
std::unique_ptr< tf2_ros::TransformListener > tf2_listener_
void updateTimeProgress(std::vector< carma_planning_msgs::msg::Maneuver > &maneuvers, rclcpp::Time start_time) const
Given an array of maneuvers update the starting time for each.
carma_planning_msgs::msg::Maneuver composeLaneChangeManeuverMessage(double start_dist, double end_dist, double start_speed, double target_speed, lanelet::Id starting_lane_id, lanelet::Id ending_lane_id) const
Compose a lane change maneuver message based on input params NOTE: The start and stop time are not se...
std::string getNewManeuverId() const
This method returns a new UUID as a string for assignment to a Maneuver message.
bool maneuverWithBufferStartsAfterDowntrack(const carma_planning_msgs::msg::Maneuver &maneuver, double downtrack, double lateral_accel, double min_maneuver_length) const
Identifies if a maneuver starts after the provided downtrack with compensation for a dynamic buffer s...
std::vector< carma_planning_msgs::msg::Maneuver > routeCb(const lanelet::routing::LaneletPath &route_shortest_path)
Calculate maneuver plan for remaining route. This callback is triggered when a new route has been rec...
carma_planning_msgs::msg::Maneuver composeLaneFollowingManeuverMessage(double start_dist, double end_dist, double start_speed, double target_speed, const std::vector< lanelet::Id > &lane_ids) const
Compose a lane keeping maneuver message based on input params.
void setManeuverStartDist(carma_planning_msgs::msg::Maneuver &maneuver, double start_dist) const
Set the start distance of a maneuver based on the progress along the route.
carma_planning_msgs::msg::ManeuverPlan::UniquePtr current_maneuver_plan_
void bumper_pose_cb()
Callback for the front bumper pose transform.
void updateStartingSpeed(carma_planning_msgs::msg::Maneuver &maneuver, double start_speed) const
Given an maneuver update the starting speed.
void current_maneuver_plan_cb(carma_planning_msgs::msg::ManeuverPlan::UniquePtr msg)
Callback for the ManeuverPlan subscriber, will store the current maneuver plan received locally....
void twist_cb(geometry_msgs::msg::TwistStamped::UniquePtr msg)
Callback for the twist subscriber, which will store latest twist locally.
void plan_maneuvers_callback(std::shared_ptr< rmw_request_id_t > srv_header, carma_planning_msgs::srv::PlanManeuvers::Request::SharedPtr req, carma_planning_msgs::srv::PlanManeuvers::Response::SharedPtr resp)
Service callback for arbitrator maneuver planning.
double findSpeedLimit(const lanelet::ConstLanelet &llt)
Given a Lanelet, find it's associated Speed Limit.
bool isLaneChangeNeeded(lanelet::routing::LaneletRelations relations, lanelet::Id target_id) const
Given a LaneletRelations and ID of the next lanelet in the shortest path.
carma_ros2_utils::SubPtr< carma_planning_msgs::msg::ManeuverPlan > current_maneuver_plan_sub_
carma_ros2_utils::CallbackReturn on_activate_plugin()
Method which is triggered when this plugin is moved from the INACTIVE to ACTIVE states....
std::shared_ptr< carma_wm::WMListener > wml_
rclcpp::Duration getManeuverDuration(carma_planning_msgs::msg::Maneuver &maneuver, double epsilon) const
returns duration as ros::Duration required to complete maneuver given its start dist,...
void returnToShortestPath(const lanelet::ConstLanelet &current_lanelet)
This method re-routes the vehicle back to the shortest path, if the vehicle has left the shortest pat...
carma_ros2_utils::SubPtr< geometry_msgs::msg::TwistStamped > twist_sub_
RouteFollowingPlugin(const rclcpp::NodeOptions &)
Default constructor for RouteFollowingPlugin class.
carma_planning_msgs::msg::Maneuver composeStopAndWaitManeuverMessage(double start_dist, double end_dist, double start_speed, lanelet::Id starting_lane_id, lanelet::Id ending_lane_id, double stopping_accel) const
Compose a stop and wait maneuver message based on input params. NOTE: The start and stop time are not...
std::vector< carma_planning_msgs::msg::Maneuver > addStopAndWaitAtRouteEnd(const std::vector< carma_planning_msgs::msg::Maneuver > &input_maneuvers, double route_end_downtrack, double stopping_entry_speed, double stopping_logitudinal_accel, double lateral_accel_limit, double min_maneuver_length) const
Adds a StopAndWait maneuver to the end of a maneuver set stopping at the provided downtrack value NOT...
bool get_availability()
Get the availability status of this plugin based on the current operating environment....
auto to_string(const UtmZone &zone) -> std::string
Definition: utm_zone.cpp:21
void setManeuverLaneletIds(carma_planning_msgs::msg::Maneuver &mvr, lanelet::Id start_id, lanelet::Id end_id)
Anonymous function to set the lanelet ids for all maneuver types except lane following.
double getManeuverEndSpeed(const carma_planning_msgs::msg::Maneuver &mvr)
Anonymous function to extract maneuver end speed which can not be optained with GET_MANEUVER_PROPERY ...
#define SET_MANEUVER_PROPERTY(mvr, property, value)
Struct containing config values values for route_following_plugin.