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::RouteFollowingPlugin Class Reference

#include <route_following_plugin.hpp>

Inheritance diagram for route_following_plugin::RouteFollowingPlugin:
Inheritance graph
Collaboration diagram for route_following_plugin::RouteFollowingPlugin:
Collaboration graph

Public Member Functions

 RouteFollowingPlugin (const rclcpp::NodeOptions &)
 Default constructor for RouteFollowingPlugin class. More...
 
carma_ros2_utils::CallbackReturn on_configure_plugin ()
 Method which is triggered when this plugin is moved from the UNCONFIGURED to INACTIVE states. This method should be used to load parameters and is required to be implemented. More...
 
carma_ros2_utils::CallbackReturn on_activate_plugin ()
 Method which is triggered when this plugin is moved from the INACTIVE to ACTIVE states. This method should be used to prepare for future callbacks for plugin's capabilites. More...
 
bool get_availability ()
 Get the availability status of this plugin based on the current operating environment. Method must be overriden by extending classes. More...
 
std::string get_version_id ()
 Returns the version id of this plugin. More...
 
- Public Member Functions inherited from carma_guidance_plugins::StrategicPlugin
 StrategicPlugin (const rclcpp::NodeOptions &)
 StrategicPlugin constructor. More...
 
virtual ~StrategicPlugin ()=default
 Virtual destructor for safe deletion. More...
 
virtual 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)=0
 Extending class provided callback which should return a planned trajectory based on the provided trajectory planning request. More...
 
std::string get_capability () override
 Get the capability string representing this plugins capabilities Method must be overriden by extending classes. Expectation is that abstract plugin type parent classes will provide a default implementation. More...
 
uint8_t get_type () override final
 Returns the type of this plugin according to the carma_planning_msgs::Plugin type enum. Extending classes for the specific type should override this method. More...
 
carma_ros2_utils::CallbackReturn handle_on_configure (const rclcpp_lifecycle::State &) override final
 
carma_ros2_utils::CallbackReturn handle_on_activate (const rclcpp_lifecycle::State &) override final
 
carma_ros2_utils::CallbackReturn handle_on_deactivate (const rclcpp_lifecycle::State &) override final
 
carma_ros2_utils::CallbackReturn handle_on_cleanup (const rclcpp_lifecycle::State &) override final
 
carma_ros2_utils::CallbackReturn handle_on_shutdown (const rclcpp_lifecycle::State &) override final
 
carma_ros2_utils::CallbackReturn handle_on_error (const rclcpp_lifecycle::State &, const std::string &exception_string) override final
 
- Public Member Functions inherited from carma_guidance_plugins::PluginBaseNode
 PluginBaseNode (const rclcpp::NodeOptions &)
 PluginBaseNode constructor. More...
 
virtual ~PluginBaseNode ()=default
 Virtual destructor for safe deletion. More...
 
virtual std::shared_ptr< carma_wm::WMListenerget_world_model_listener () final
 Method to return the default world model listener provided as a convience by this base class If this method or get_world_model() are not called then the world model remains uninitialized and will not create unnecessary subscriptions. More...
 
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 get_world_model_listener() are not called then the world model remains uninitialized and will not create unnecessary subscriptions. More...
 
virtual bool get_activation_status () final
 Returns the activation status of this plugin. The plugins API callbacks will only be triggered when this method returns true. More...
 
virtual uint8_t get_type ()
 Returns the type of this plugin according to the carma_planning_msgs::Plugin type enum. Extending classes for the specific type should override this method. More...
 
std::string get_plugin_name_and_ns () const
 Return the name of this plugin with namespace. NOTE: If only the name of the plugin is required, use get_plugin_name() More...
 
std::string get_plugin_name () const
 Return the name of this plugin. More...
 
virtual bool get_availability ()=0
 Get the availability status of this plugin based on the current operating environment. Method must be overriden by extending classes. More...
 
virtual std::string get_capability ()=0
 Get the capability string representing this plugins capabilities Method must be overriden by extending classes. Expectation is that abstract plugin type parent classes will provide a default implementation. More...
 
virtual std::string get_version_id ()=0
 Returns the version id of this plugin. More...
 
virtual carma_ros2_utils::CallbackReturn on_configure_plugin ()=0
 Method which is triggered when this plugin is moved from the UNCONFIGURED to INACTIVE states. This method should be used to load parameters and is required to be implemented. More...
 
virtual carma_ros2_utils::CallbackReturn on_activate_plugin ()
 Method which is triggered when this plugin is moved from the INACTIVE to ACTIVE states. This method should be used to prepare for future callbacks for plugin's capabilites. More...
 
virtual carma_ros2_utils::CallbackReturn on_deactivate_plugin ()
 Method which is triggered when this plugin is moved from the ACTIVE to INACTIVE states. This method should be used to disable any functionality which should cease execution when plugin is inactive. More...
 
virtual carma_ros2_utils::CallbackReturn on_cleanup_plugin ()
 Method which is triggered when this plugin is moved from the INACTIVE to UNCONFIGURED states. This method should be used to fully reset the plugin such that a future call to on_configure_plugin would leave the plugin in a fresh state as though just launched. More...
 
virtual carma_ros2_utils::CallbackReturn on_shutdown_plugin ()
 Method which is triggered when this plugin is moved from any state to FINALIZED This method should be used to generate any shutdown logs or final cleanup. More...
 
virtual carma_ros2_utils::CallbackReturn on_error_plugin (const std::string &exception_string)
 Method which is triggered when an unhandled exception occurs in this plugin This method should be used to cleanup such that the plugin could be moved to UNCONFIGURED state if possible. More...
 
carma_ros2_utils::CallbackReturn handle_on_configure (const rclcpp_lifecycle::State &) override
 
carma_ros2_utils::CallbackReturn handle_on_activate (const rclcpp_lifecycle::State &) override
 
carma_ros2_utils::CallbackReturn handle_on_deactivate (const rclcpp_lifecycle::State &) override
 
carma_ros2_utils::CallbackReturn handle_on_cleanup (const rclcpp_lifecycle::State &) override
 
carma_ros2_utils::CallbackReturn handle_on_shutdown (const rclcpp_lifecycle::State &) override
 
carma_ros2_utils::CallbackReturn handle_on_error (const rclcpp_lifecycle::State &, const std::string &exception_string) override
 
 FRIEND_TEST (carma_guidance_plugins_test, connections_test)
 

Public Attributes

std::shared_ptr< carma_wm::WMListenerwml_
 
carma_wm::WorldModelConstPtr wm_
 

Private Member Functions

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. More...
 
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 set. This is because this is recomputed based on requests from the arbitrator. More...
 
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 set. This is because this is recomputed based on requests from the arbitrator. More...
 
bool isLaneChangeNeeded (lanelet::routing::LaneletRelations relations, lanelet::Id target_id) const
 Given a LaneletRelations and ID of the next lanelet in the shortest path. More...
 
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. More...
 
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. More...
 
void updateStartingSpeed (carma_planning_msgs::msg::Maneuver &maneuver, double start_speed) const
 Given an maneuver update the starting speed. More...
 
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. More...
 
double findSpeedLimit (const lanelet::ConstLanelet &llt)
 Given a Lanelet, find it's associated Speed Limit. More...
 
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 received and processed by the world model. More...
 
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 NOTE: The priority of this method is to plan the stopping maneuver therefore earlier maneuvers will be modified or removed if required to allow the stopping behavior to be executed. More...
 
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 size based on the maneuver type. More...
 
std::string getNewManeuverId () const
 This method returns a new UUID as a string for assignment to a Maneuver message. More...
 
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 path, but is still on the route Re-routing is performed by generating a new shortest path via the closest lanelet on the original shortest path. More...
 
void bumper_pose_cb ()
 Callback for the front bumper pose transform. More...
 
void twist_cb (geometry_msgs::msg::TwistStamped::UniquePtr msg)
 Callback for the twist subscriber, which will store latest twist locally. More...
 
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. Used as part of the detection system for differentiating leaving the shortest path via another plugin vs. control drift taking the vehicle's reference point outside of the intended lane. More...
 
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, end dist, start speed and end speed More...
 
void initializeBumperTransformLookup ()
 Initialize transform lookup from front bumper to map. More...
 
 FRIEND_TEST (RouteFollowingPluginTest, testComposeManeuverMessage)
 
 FRIEND_TEST (RouteFollowingPluginTest, testIdentifyLaneChange)
 
 FRIEND_TEST (RouteFollowingPlugin, TestAssociateSpeedLimit)
 
 FRIEND_TEST (RouteFollowingPlugin, TestAssociateSpeedLimitusingosm)
 
 FRIEND_TEST (RouteFollowingPlugin, TestHelperfunctions)
 
 FRIEND_TEST (RouteFollowingPlugin, TestReturnToShortestPath)
 
 FRIEND_TEST (StopAndWaitTestFixture, CaseOne)
 
 FRIEND_TEST (StopAndWaitTestFixture, CaseTwo)
 
 FRIEND_TEST (StopAndWaitTestFixture, CaseThree)
 
 FRIEND_TEST (StopAndWaitTestFixture, CaseFour)
 
 FRIEND_TEST (StopAndWaitTestFixture, CaseFive)
 
 FRIEND_TEST (StopAndWaitTestFixture, CaseSix)
 
 FRIEND_TEST (StopAndWaitTestFixture, CaseSeven)
 
 FRIEND_TEST (StopAndWaitTestFixture, CaseEight)
 
 FRIEND_TEST (StopAndWaitTestFixture, CaseNine)
 
 FRIEND_TEST (StopAndWaitTestFixture, CaseTen)
 

Private Attributes

carma_ros2_utils::SubPtr< geometry_msgs::msg::TwistStamped > twist_sub_
 
carma_ros2_utils::SubPtr< carma_planning_msgs::msg::ManeuverPlan > current_maneuver_plan_sub_
 
std::unordered_set< lanelet::Id > shortest_path_set_
 
Config config_
 
double current_speed_ = 0.0
 
double epsilon_ = 0.0001
 
geometry_msgs::msg::PoseStamped pose_msg_
 
lanelet::BasicPoint2d current_loc_
 
carma_planning_msgs::msg::ManeuverPlan::UniquePtr current_maneuver_plan_
 
std::vector< carma_planning_msgs::msg::Maneuver > latest_maneuver_plan_
 
std::string lane_change_plugin_ = "cooperative_lanechange"
 
std::string stop_and_wait_plugin_ = "stop_and_wait_plugin"
 
std::string planning_strategic_plugin_ = "route_following_plugin"
 
std::string lanefollow_planning_tactical_plugin_ = "inlanecruising_plugin"
 
rclcpp::TimerBase::SharedPtr bumper_pose_timer_
 
geometry_msgs::msg::TransformStamped tf_
 
tf2::Stamped< tf2::Transform > frontbumper_transform_
 
tf2_ros::Buffer tf2_buffer_
 
std::unique_ptr< tf2_ros::TransformListener > tf2_listener_
 

Static Private Attributes

static constexpr double MAX_LANE_WIDTH = 3.70
 

Detailed Description

Definition at line 62 of file route_following_plugin.hpp.

Constructor & Destructor Documentation

◆ RouteFollowingPlugin()

route_following_plugin::RouteFollowingPlugin::RouteFollowingPlugin ( const rclcpp::NodeOptions &  options)
explicit

Default constructor for RouteFollowingPlugin class.

Definition at line 88 of file route_following_plugin.cpp.

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 }
StrategicPlugin base class which can be extended by user provided plugins which wish to implement the...

References route_following_plugin::Config::accel_limit_, config_, route_following_plugin::Config::lane_change_plugin_, route_following_plugin::Config::lanefollow_planning_tactical_plugin_, route_following_plugin::Config::lateral_accel_limit_, route_following_plugin::Config::min_maneuver_length_, route_following_plugin::Config::min_plan_duration_, route_following_plugin::Config::route_end_point_buffer_, route_following_plugin::Config::stop_and_wait_plugin_, route_following_plugin::Config::stopping_accel_limit_multiplier_, and route_following_plugin::Config::vehicle_id.

Member Function Documentation

◆ addStopAndWaitAtRouteEnd()

std::vector< carma_planning_msgs::msg::Maneuver > route_following_plugin::RouteFollowingPlugin::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
private

Adds a StopAndWait maneuver to the end of a maneuver set stopping at the provided downtrack value NOTE: The priority of this method is to plan the stopping maneuver therefore earlier maneuvers will be modified or removed if required to allow the stopping behavior to be executed.

Parameters
input_maneuversThe set of maneuvers to modify to support the StopAndWait maneuver.
route_end_downtrackThe target stopping point (normally the end of the route) which the vehicle should stop before. Units meters
stopping_entry_speedThe expected entry speed for stopping. This is used to compute the stopping distance. Units m/s
stopping_logitudinal_accelThe target deceleration (unsigned) for the stopping operation. Units m/s/s
lateral_accel_limitThe lateral acceleration limit allowed for lane changes. Units m/s/s
min_maneuver_lengthThe absolute minimum allowable maneuver length for any existing maneuvers in meters

NOTE: Only min_maneuver_length can be a zero-valued input. All other parameters must be positive values greater than zero.

Exceptions
std::invalid_argumentIf existing maneuvers cannot be modified to allow stopping maneuver creation, or if the generated maneuvers do not overlap any lanelets in the map.
Returns
A list of maneuvers which mirrors the input list but with the modifications required to include a stopping maneuver at the end

ASSUMPTION: At the moment the stopping entry speed is not updated because the assumption is that any previous maneuvers which were slower need not be accounted for as planning for a higher speed will always be capable of handling that case and any which were faster would already have their speed reduced by the maneuver which this speed was derived from.

Alogirthm in this block is as follows

  1. Compute distance to slowdown to stop at acceleration limit
  2. Drop maneuvers which are wholly encompassed in stopping distance
  3. If end downtrack - stop distance is > last maneuver end distance then fill delta with lane follow followed by stop and wait
  4. If end downtrack - stop distance is < last maneuver end distance then reduce the existing maneuver to allow for stopping maneuver to be planned
  5. Add maneuver to list

Definition at line 265 of file route_following_plugin.cpp.

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 }
#define GET_MANEUVER_PROPERTY(mvr, property)
Macro definition to enable easier access to fields shared across the maneuver types.
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...
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.
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...
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.
#define SET_MANEUVER_PROPERTY(mvr, property, value)

References composeLaneFollowingManeuverMessage(), composeStopAndWaitManeuverMessage(), config_, GET_MANEUVER_PROPERTY, maneuverWithBufferStartsAfterDowntrack(), route_following_plugin::Config::min_maneuver_length_, SET_MANEUVER_PROPERTY, route_following_plugin::anonymous_namespace{route_following_plugin.cpp}::setManeuverLaneletIds(), carma_cooperative_perception::to_string(), and wm_.

Referenced by routeCb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ bumper_pose_cb()

void route_following_plugin::RouteFollowingPlugin::bumper_pose_cb ( )
private

Callback for the front bumper pose transform.

Definition at line 531 of file route_following_plugin.cpp.

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 }
std::vector< carma_planning_msgs::msg::Maneuver > latest_maneuver_plan_
std::unordered_set< lanelet::Id > shortest_path_set_
carma_planning_msgs::msg::ManeuverPlan::UniquePtr current_maneuver_plan_
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...

References current_loc_, current_maneuver_plan_, frontbumper_transform_, GET_MANEUVER_PROPERTY, process_bag::i, latest_maneuver_plan_, planning_strategic_plugin_, returnToShortestPath(), shortest_path_set_, tf2_buffer_, tf_, and wm_.

Referenced by on_activate_plugin().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ composeLaneChangeManeuverMessage()

carma_planning_msgs::msg::Maneuver route_following_plugin::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
private

Compose a lane change maneuver message based on input params NOTE: The start and stop time are not set. This is because this is recomputed based on requests from the arbitrator.

Parameters
start_distStart downtrack distance of the current maneuver
end_distEnd downtrack distance of the current maneuver
start_speedStart speed of the current maneuver
start_lane_idStarting Lanelet ID of the current maneuver
ending_lane_idEnding Lanelet ID of the current maneuver
target_speedTarget speed of the current maneuver
Returns
A lane keeping maneuver message which is ready to be published

Definition at line 753 of file route_following_plugin.cpp.

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 }
std::string getNewManeuverId() const
This method returns a new UUID as a string for assignment to a Maneuver message.

References getNewManeuverId(), lane_change_plugin_, planning_strategic_plugin_, and carma_cooperative_perception::to_string().

Referenced by routeCb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ composeLaneFollowingManeuverMessage()

carma_planning_msgs::msg::Maneuver route_following_plugin::RouteFollowingPlugin::composeLaneFollowingManeuverMessage ( double  start_dist,
double  end_dist,
double  start_speed,
double  target_speed,
const std::vector< lanelet::Id > &  lane_ids 
) const
private

Compose a lane keeping maneuver message based on input params.

Parameters
start_distStart downtrack distance of the current maneuver
end_distEnd downtrack distance of the current maneuver
start_speedStart speed of the current maneuver
target_speedTarget speed pf the current maneuver, usually it is the lanelet speed limit
lane_idsList of lanelet IDs that the current maneuver traverses. Message expects these to be contiguous and end to end
Returns
A lane keeping maneuver message which is ready to be published

Definition at line 724 of file route_following_plugin.cpp.

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 }

References getNewManeuverId(), lanefollow_planning_tactical_plugin_, planning_strategic_plugin_, and carma_cooperative_perception::to_string().

Referenced by addStopAndWaitAtRouteEnd(), and routeCb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ composeStopAndWaitManeuverMessage()

carma_planning_msgs::msg::Maneuver route_following_plugin::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
private

Compose a stop and wait maneuver message based on input params. NOTE: The start and stop time are not set. This is because this is recomputed based on requests from the arbitrator.

Parameters
start_distStart downtrack distance of the current maneuver
end_distEnd downtrack distance of the current maneuver
start_speedStart speed of the current maneuver
start_lane_idStarting Lanelet ID of the current maneuver
ending_lane_idEnding Lanelet ID of the current maneuver
stopping_accelAcceleration used for calculating the stopping distance
Returns
A lane keeping maneuver message which is ready to be published

Definition at line 784 of file route_following_plugin.cpp.

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 }

References config_, getNewManeuverId(), planning_strategic_plugin_, route_following_plugin::Config::route_end_point_buffer_, stop_and_wait_plugin_, and carma_cooperative_perception::to_string().

Referenced by addStopAndWaitAtRouteEnd().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ current_maneuver_plan_cb()

void route_following_plugin::RouteFollowingPlugin::current_maneuver_plan_cb ( carma_planning_msgs::msg::ManeuverPlan::UniquePtr  msg)
private

Callback for the ManeuverPlan subscriber, will store the current maneuver plan received locally. Used as part of the detection system for differentiating leaving the shortest path via another plugin vs. control drift taking the vehicle's reference point outside of the intended lane.

Parameters
msgLatest ManeuverPlan message

Definition at line 165 of file route_following_plugin.cpp.

165 {
166 current_maneuver_plan_ = std::move(msg);
167 }

References current_maneuver_plan_.

Referenced by on_configure_plugin().

Here is the caller graph for this function:

◆ findSpeedLimit()

double route_following_plugin::RouteFollowingPlugin::findSpeedLimit ( const lanelet::ConstLanelet &  llt)
private

Given a Lanelet, find it's associated Speed Limit.

Parameters
lltConstant Lanelet object
Returns
value of speed limit in mps

Definition at line 826 of file route_following_plugin.cpp.

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 }

References wm_.

Referenced by routeCb().

Here is the caller graph for this function:

◆ FRIEND_TEST() [1/16]

route_following_plugin::RouteFollowingPlugin::FRIEND_TEST ( RouteFollowingPlugin  ,
TestAssociateSpeedLimit   
)
private

◆ FRIEND_TEST() [2/16]

route_following_plugin::RouteFollowingPlugin::FRIEND_TEST ( RouteFollowingPlugin  ,
TestAssociateSpeedLimitusingosm   
)
private

◆ FRIEND_TEST() [3/16]

route_following_plugin::RouteFollowingPlugin::FRIEND_TEST ( RouteFollowingPlugin  ,
TestHelperfunctions   
)
private

◆ FRIEND_TEST() [4/16]

route_following_plugin::RouteFollowingPlugin::FRIEND_TEST ( RouteFollowingPlugin  ,
TestReturnToShortestPath   
)
private

◆ FRIEND_TEST() [5/16]

route_following_plugin::RouteFollowingPlugin::FRIEND_TEST ( RouteFollowingPluginTest  ,
testComposeManeuverMessage   
)
private

◆ FRIEND_TEST() [6/16]

route_following_plugin::RouteFollowingPlugin::FRIEND_TEST ( RouteFollowingPluginTest  ,
testIdentifyLaneChange   
)
private

◆ FRIEND_TEST() [7/16]

route_following_plugin::RouteFollowingPlugin::FRIEND_TEST ( StopAndWaitTestFixture  ,
CaseEight   
)
private

◆ FRIEND_TEST() [8/16]

route_following_plugin::RouteFollowingPlugin::FRIEND_TEST ( StopAndWaitTestFixture  ,
CaseFive   
)
private

◆ FRIEND_TEST() [9/16]

route_following_plugin::RouteFollowingPlugin::FRIEND_TEST ( StopAndWaitTestFixture  ,
CaseFour   
)
private

◆ FRIEND_TEST() [10/16]

route_following_plugin::RouteFollowingPlugin::FRIEND_TEST ( StopAndWaitTestFixture  ,
CaseNine   
)
private

◆ FRIEND_TEST() [11/16]

route_following_plugin::RouteFollowingPlugin::FRIEND_TEST ( StopAndWaitTestFixture  ,
CaseOne   
)
private

◆ FRIEND_TEST() [12/16]

route_following_plugin::RouteFollowingPlugin::FRIEND_TEST ( StopAndWaitTestFixture  ,
CaseSeven   
)
private

◆ FRIEND_TEST() [13/16]

route_following_plugin::RouteFollowingPlugin::FRIEND_TEST ( StopAndWaitTestFixture  ,
CaseSix   
)
private

◆ FRIEND_TEST() [14/16]

route_following_plugin::RouteFollowingPlugin::FRIEND_TEST ( StopAndWaitTestFixture  ,
CaseTen   
)
private

◆ FRIEND_TEST() [15/16]

route_following_plugin::RouteFollowingPlugin::FRIEND_TEST ( StopAndWaitTestFixture  ,
CaseThree   
)
private

◆ FRIEND_TEST() [16/16]

route_following_plugin::RouteFollowingPlugin::FRIEND_TEST ( StopAndWaitTestFixture  ,
CaseTwo   
)
private

◆ get_availability()

bool route_following_plugin::RouteFollowingPlugin::get_availability ( )
virtual

Get the availability status of this plugin based on the current operating environment. Method must be overriden by extending classes.

Returns
This method should return true if the plugin's current understanding of the world means it would be capable of planning or executing its capability.

Implements carma_guidance_plugins::PluginBaseNode.

Definition at line 403 of file route_following_plugin.cpp.

404 {
405 return true;
406 }

◆ get_version_id()

std::string route_following_plugin::RouteFollowingPlugin::get_version_id ( )
virtual

Returns the version id of this plugin.

Returns
The version id represented as a string

Implements carma_guidance_plugins::PluginBaseNode.

Definition at line 408 of file route_following_plugin.cpp.

409 {
410 return "v1.0";
411 }

◆ getManeuverDuration()

rclcpp::Duration route_following_plugin::RouteFollowingPlugin::getManeuverDuration ( carma_planning_msgs::msg::Maneuver &  maneuver,
double  epsilon 
) const
private

returns duration as ros::Duration required to complete maneuver given its start dist, end dist, start speed and end speed

Parameters
maneuverThe maneuver message to calculate duration for
epsilonThe acceptable min start_speed + target_speed in the maneuver message, under which the maneuver is treated as faulty. Throws exception if sum of start and target speed of maneuver is below limit defined by parameter epsilon

Definition at line 609 of file route_following_plugin.cpp.

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 }
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 ...

References GET_MANEUVER_PROPERTY, and route_following_plugin::anonymous_namespace{route_following_plugin.cpp}::getManeuverEndSpeed().

Referenced by plan_maneuvers_callback(), and updateTimeProgress().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getNewManeuverId()

std::string route_following_plugin::RouteFollowingPlugin::getNewManeuverId ( ) const
private

This method returns a new UUID as a string for assignment to a Maneuver message.

Returns
A new UUID as a string

Definition at line 778 of file route_following_plugin.cpp.

778 {
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 }

Referenced by composeLaneChangeManeuverMessage(), composeLaneFollowingManeuverMessage(), and composeStopAndWaitManeuverMessage().

Here is the caller graph for this function:

◆ initializeBumperTransformLookup()

void route_following_plugin::RouteFollowingPlugin::initializeBumperTransformLookup ( )
private

Initialize transform lookup from front bumper to map.

Definition at line 839 of file route_following_plugin.cpp.

840 {
841 tf2_listener_.reset(new tf2_ros::TransformListener(tf2_buffer_));
842 tf2_buffer_.setUsingDedicatedThread(true);
843 }
std::unique_ptr< tf2_ros::TransformListener > tf2_listener_

References tf2_buffer_, and tf2_listener_.

Referenced by on_configure_plugin().

Here is the caller graph for this function:

◆ isLaneChangeNeeded()

bool route_following_plugin::RouteFollowingPlugin::isLaneChangeNeeded ( lanelet::routing::LaneletRelations  relations,
lanelet::Id  target_id 
) const
private

Given a LaneletRelations and ID of the next lanelet in the shortest path.

Parameters
relationsLaneletRelations relative to the previous lanelet
target_idID of the next lanelet in the shortest path
Returns
Whether we need a lanechange to reach to the next lanelet in the shortest path.

Definition at line 813 of file route_following_plugin.cpp.

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 }

Referenced by routeCb().

Here is the caller graph for this function:

◆ maneuverWithBufferStartsAfterDowntrack()

bool route_following_plugin::RouteFollowingPlugin::maneuverWithBufferStartsAfterDowntrack ( const carma_planning_msgs::msg::Maneuver &  maneuver,
double  downtrack,
double  lateral_accel,
double  min_maneuver_length 
) const
private

Identifies if a maneuver starts after the provided downtrack with compensation for a dynamic buffer size based on the maneuver type.

Parameters
maneuverThe maneuver to compare
downtrackThe downtrack value to evaluate in meters
lateral_accelThe max lateral acceleration allowed for lane changes in m/s/s
min_maneuver_lengthThe absolute minimum allowable for any maneuver in meters
Returns
true if the provided maneuver plus the computed dynamic buffer starts after the provided downtrack value

Definition at line 381 of file route_following_plugin.cpp.

381 {
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 }

References GET_MANEUVER_PROPERTY, route_following_plugin::anonymous_namespace{route_following_plugin.cpp}::getManeuverEndSpeed(), and MAX_LANE_WIDTH.

Referenced by addStopAndWaitAtRouteEnd().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ on_activate_plugin()

carma_ros2_utils::CallbackReturn route_following_plugin::RouteFollowingPlugin::on_activate_plugin ( )
virtual

Method which is triggered when this plugin is moved from the INACTIVE to ACTIVE states. This method should be used to prepare for future callbacks for plugin's capabilites.

Returns
SUCCESS, FAILURE, or ERROR. Transition to ACTIVE will only complete on SUCCESS.

Reimplemented from carma_guidance_plugins::PluginBaseNode.

Definition at line 150 of file route_following_plugin.cpp.

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 }
void bumper_pose_cb()
Callback for the front bumper pose transform.

References bumper_pose_cb(), and bumper_pose_timer_.

Here is the call graph for this function:

◆ on_configure_plugin()

carma_ros2_utils::CallbackReturn route_following_plugin::RouteFollowingPlugin::on_configure_plugin ( )
virtual

Method which is triggered when this plugin is moved from the UNCONFIGURED to INACTIVE states. This method should be used to load parameters and is required to be implemented.

Returns
SUCCESS, FAILURE, or ERROR. Transition to INACTIVE will only complete on SUCCESS.

Implements carma_guidance_plugins::PluginBaseNode.

Definition at line 104 of file route_following_plugin.cpp.

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 }
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 ...
void initializeBumperTransformLookup()
Initialize transform lookup from front bumper to map.
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...
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.
carma_ros2_utils::SubPtr< carma_planning_msgs::msg::ManeuverPlan > current_maneuver_plan_sub_
std::shared_ptr< carma_wm::WMListener > wml_
carma_ros2_utils::SubPtr< geometry_msgs::msg::TwistStamped > twist_sub_

References route_following_plugin::Config::accel_limit_, config_, current_maneuver_plan_cb(), current_maneuver_plan_sub_, carma_guidance_plugins::PluginBaseNode::get_world_model(), carma_guidance_plugins::PluginBaseNode::get_world_model_listener(), initializeBumperTransformLookup(), route_following_plugin::Config::lane_change_plugin_, route_following_plugin::Config::lanefollow_planning_tactical_plugin_, route_following_plugin::Config::lateral_accel_limit_, latest_maneuver_plan_, route_following_plugin::Config::min_maneuver_length_, route_following_plugin::Config::min_plan_duration_, route_following_plugin::Config::route_end_point_buffer_, routeCb(), route_following_plugin::Config::stop_and_wait_plugin_, route_following_plugin::Config::stopping_accel_limit_multiplier_, twist_cb(), twist_sub_, wm_, and wml_.

Here is the call graph for this function:

◆ plan_maneuvers_callback()

void route_following_plugin::RouteFollowingPlugin::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 
)
privatevirtual

Service callback for arbitrator maneuver planning.

Parameters
reqPlan maneuver request
respPlan maneuver response with a list of maneuver plan
Returns
If service call successed

Implements carma_guidance_plugins::StrategicPlugin.

Definition at line 413 of file route_following_plugin.cpp.

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 }
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.
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.
void updateStartingSpeed(carma_planning_msgs::msg::Maneuver &maneuver, double start_speed) const
Given an maneuver update the starting speed.
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,...

References config_, epsilon_, GET_MANEUVER_PROPERTY, getManeuverDuration(), process_bag::i, latest_maneuver_plan_, route_following_plugin::Config::min_plan_duration_, setManeuverStartDist(), carma_cooperative_perception::to_string(), updateStartingSpeed(), and updateTimeProgress().

Here is the call graph for this function:

◆ returnToShortestPath()

void route_following_plugin::RouteFollowingPlugin::returnToShortestPath ( const lanelet::ConstLanelet &  current_lanelet)
private

This method re-routes the vehicle back to the shortest path, if the vehicle has left the shortest path, but is still on the route Re-routing is performed by generating a new shortest path via the closest lanelet on the original shortest path.

Parameters
current_laneletcurretn lanelet where the vehicle is at

Definition at line 845 of file route_following_plugin.cpp.

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 }

References latest_maneuver_plan_, routeCb(), shortest_path_set_, and wm_.

Referenced by bumper_pose_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ routeCb()

std::vector< carma_planning_msgs::msg::Maneuver > route_following_plugin::RouteFollowingPlugin::routeCb ( const lanelet::routing::LaneletPath &  route_shortest_path)
private

Calculate maneuver plan for remaining route. This callback is triggered when a new route has been received and processed by the world model.

Parameters
route_shortest_pathA list of lanelets along the shortest path of the route using which the maneuver plan is calculated.

Definition at line 169 of file route_following_plugin.cpp.

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 }
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...
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.
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...

References route_following_plugin::Config::accel_limit_, addStopAndWaitAtRouteEnd(), composeLaneChangeManeuverMessage(), composeLaneFollowingManeuverMessage(), config_, current_loc_, current_speed_, findSpeedLimit(), GET_MANEUVER_PROPERTY, route_following_plugin::anonymous_namespace{route_following_plugin.cpp}::getManeuverEndSpeed(), isLaneChangeNeeded(), route_following_plugin::Config::lateral_accel_limit_, route_following_plugin::Config::min_maneuver_length_, shortest_path_set_, route_following_plugin::Config::stopping_accel_limit_multiplier_, and wm_.

Referenced by on_configure_plugin(), and returnToShortestPath().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ setManeuverStartDist()

void route_following_plugin::RouteFollowingPlugin::setManeuverStartDist ( carma_planning_msgs::msg::Maneuver &  maneuver,
double  start_dist 
) const
private

Set the start distance of a maneuver based on the progress along the route.

Parameters
maneuverA maneuver (non-specific to type) to be performed
start_distthe starting distance that the maneuver need to be updated to

Definition at line 697 of file route_following_plugin.cpp.

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 }

Referenced by plan_maneuvers_callback().

Here is the caller graph for this function:

◆ twist_cb()

void route_following_plugin::RouteFollowingPlugin::twist_cb ( geometry_msgs::msg::TwistStamped::UniquePtr  msg)
private

Callback for the twist subscriber, which will store latest twist locally.

Parameters
msgLatest twist message

Definition at line 160 of file route_following_plugin.cpp.

161 {
162 current_speed_ = msg->twist.linear.x;
163 }

References current_speed_.

Referenced by on_configure_plugin().

Here is the caller graph for this function:

◆ updateStartingSpeed()

void route_following_plugin::RouteFollowingPlugin::updateStartingSpeed ( carma_planning_msgs::msg::Maneuver &  maneuver,
double  start_speed 
) const
private

Given an maneuver update the starting speed.

Parameters
maneuvermaneuver to update the starting speed for
start_timeThe starting speed for the maneuver passed as argument

Definition at line 670 of file route_following_plugin.cpp.

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 }

Referenced by plan_maneuvers_callback().

Here is the caller graph for this function:

◆ updateTimeProgress()

void route_following_plugin::RouteFollowingPlugin::updateTimeProgress ( std::vector< carma_planning_msgs::msg::Maneuver > &  maneuvers,
rclcpp::Time  start_time 
) const
private

Given an array of maneuvers update the starting time for each.

Parameters
maneuversAn array of maneuvers (non-specific to type)
start_timeThe starting time for the first maneuver in the sequence, each consequent maneuver is pushed ahead by same amount

Definition at line 628 of file route_following_plugin.cpp.

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 }

References epsilon_, and getManeuverDuration().

Referenced by plan_maneuvers_callback().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ bumper_pose_timer_

rclcpp::TimerBase::SharedPtr route_following_plugin::RouteFollowingPlugin::bumper_pose_timer_
private

Definition at line 264 of file route_following_plugin.hpp.

Referenced by on_activate_plugin().

◆ config_

Config route_following_plugin::RouteFollowingPlugin::config_
private

◆ current_loc_

lanelet::BasicPoint2d route_following_plugin::RouteFollowingPlugin::current_loc_
private

Definition at line 248 of file route_following_plugin.hpp.

Referenced by bumper_pose_cb(), and routeCb().

◆ current_maneuver_plan_

carma_planning_msgs::msg::ManeuverPlan::UniquePtr route_following_plugin::RouteFollowingPlugin::current_maneuver_plan_
private

Definition at line 251 of file route_following_plugin.hpp.

Referenced by bumper_pose_cb(), and current_maneuver_plan_cb().

◆ current_maneuver_plan_sub_

carma_ros2_utils::SubPtr<carma_planning_msgs::msg::ManeuverPlan> route_following_plugin::RouteFollowingPlugin::current_maneuver_plan_sub_
private

Definition at line 230 of file route_following_plugin.hpp.

Referenced by on_configure_plugin().

◆ current_speed_

double route_following_plugin::RouteFollowingPlugin::current_speed_ = 0.0
private

Definition at line 241 of file route_following_plugin.hpp.

Referenced by routeCb(), and twist_cb().

◆ epsilon_

double route_following_plugin::RouteFollowingPlugin::epsilon_ = 0.0001
private

Definition at line 244 of file route_following_plugin.hpp.

Referenced by plan_maneuvers_callback(), and updateTimeProgress().

◆ frontbumper_transform_

tf2::Stamped<tf2::Transform> route_following_plugin::RouteFollowingPlugin::frontbumper_transform_
private

Definition at line 301 of file route_following_plugin.hpp.

Referenced by bumper_pose_cb().

◆ lane_change_plugin_

std::string route_following_plugin::RouteFollowingPlugin::lane_change_plugin_ = "cooperative_lanechange"
private

Definition at line 257 of file route_following_plugin.hpp.

Referenced by composeLaneChangeManeuverMessage().

◆ lanefollow_planning_tactical_plugin_

std::string route_following_plugin::RouteFollowingPlugin::lanefollow_planning_tactical_plugin_ = "inlanecruising_plugin"
private

Definition at line 261 of file route_following_plugin.hpp.

Referenced by composeLaneFollowingManeuverMessage().

◆ latest_maneuver_plan_

std::vector<carma_planning_msgs::msg::Maneuver> route_following_plugin::RouteFollowingPlugin::latest_maneuver_plan_
private

◆ MAX_LANE_WIDTH

constexpr double route_following_plugin::RouteFollowingPlugin::MAX_LANE_WIDTH = 3.70
staticconstexprprivate

Definition at line 235 of file route_following_plugin.hpp.

Referenced by maneuverWithBufferStartsAfterDowntrack().

◆ planning_strategic_plugin_

std::string route_following_plugin::RouteFollowingPlugin::planning_strategic_plugin_ = "route_following_plugin"
private

◆ pose_msg_

geometry_msgs::msg::PoseStamped route_following_plugin::RouteFollowingPlugin::pose_msg_
private

Definition at line 247 of file route_following_plugin.hpp.

◆ shortest_path_set_

std::unordered_set<lanelet::Id> route_following_plugin::RouteFollowingPlugin::shortest_path_set_
private

Definition at line 233 of file route_following_plugin.hpp.

Referenced by bumper_pose_cb(), returnToShortestPath(), and routeCb().

◆ stop_and_wait_plugin_

std::string route_following_plugin::RouteFollowingPlugin::stop_and_wait_plugin_ = "stop_and_wait_plugin"
private

Definition at line 258 of file route_following_plugin.hpp.

Referenced by composeStopAndWaitManeuverMessage().

◆ tf2_buffer_

tf2_ros::Buffer route_following_plugin::RouteFollowingPlugin::tf2_buffer_
private

Definition at line 304 of file route_following_plugin.hpp.

Referenced by bumper_pose_cb(), and initializeBumperTransformLookup().

◆ tf2_listener_

std::unique_ptr<tf2_ros::TransformListener> route_following_plugin::RouteFollowingPlugin::tf2_listener_
private

Definition at line 305 of file route_following_plugin.hpp.

Referenced by initializeBumperTransformLookup().

◆ tf_

geometry_msgs::msg::TransformStamped route_following_plugin::RouteFollowingPlugin::tf_
private

Definition at line 298 of file route_following_plugin.hpp.

Referenced by bumper_pose_cb().

◆ twist_sub_

carma_ros2_utils::SubPtr<geometry_msgs::msg::TwistStamped> route_following_plugin::RouteFollowingPlugin::twist_sub_
private

Definition at line 229 of file route_following_plugin.hpp.

Referenced by on_configure_plugin().

◆ wm_

carma_wm::WorldModelConstPtr route_following_plugin::RouteFollowingPlugin::wm_

◆ wml_

std::shared_ptr<carma_wm::WMListener> route_following_plugin::RouteFollowingPlugin::wml_

Definition at line 76 of file route_following_plugin.hpp.

Referenced by on_configure_plugin().


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