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.
basic_autonomy::waypoint_generation Namespace Reference

Classes

struct  DetailedTrajConfig
 
struct  GeneralTrajConfig
 
struct  PointSpeedPair
 

Functions

std::vector< double > apply_speed_limits (const std::vector< double > speeds, const std::vector< double > speed_limits)
 Applies the provided speed limits to the provided speeds such that each element is capped at its corresponding speed limit if needed. More...
 
Eigen::Isometry2d compute_heading_frame (const lanelet::BasicPoint2d &p1, const lanelet::BasicPoint2d &p2)
 Returns a 2D coordinate frame which is located at p1 and oriented so p2 lies on the +X axis. More...
 
std::vector< PointSpeedPairconstrain_to_time_boundary (const std::vector< PointSpeedPair > &points, double time_span)
 Reduces the input points to only those points that fit within the provided time boundary. More...
 
std::pair< double, size_t > min_with_exclusions (const std::vector< double > &values, const std::unordered_set< size_t > &excluded)
 Returns the min, and its idx, from the vector of values, excluding given set of values. More...
 
std::vector< double > optimize_speed (const std::vector< double > &downtracks, const std::vector< double > &curv_speeds, double accel_limit)
 Applies the longitudinal acceleration limit to each point's speed. More...
 
std::vector< carma_planning_msgs::msg::TrajectoryPlanPoint > trajectory_from_points_times_orientations (const std::vector< lanelet::BasicPoint2d > &points, const std::vector< double > &times, const std::vector< double > &yaws, rclcpp::Time startTime, const std::string &desired_controller_plugin)
 Method combines input points, times, orientations, and an absolute start time to form a valid carma platform trajectory. More...
 
std::vector< PointSpeedPairattach_past_points (const std::vector< PointSpeedPair > &points_set, std::vector< PointSpeedPair > future_points, const int nearest_pt_index, double back_distance)
 Attaches back_distance length of points behind the future points. More...
 
std::unique_ptr< basic_autonomy::smoothing::SplineIcompute_fit (const std::vector< lanelet::BasicPoint2d > &basic_points)
 Computes a spline based on the provided points. More...
 
double compute_curvature_at (const basic_autonomy::smoothing::SplineI &fit_curve, double step_along_the_curve)
 Given the curvature fit, computes the curvature at the given step along the curve. More...
 
std::vector< PointSpeedPaircreate_geometry_profile (const std::vector< carma_planning_msgs::msg::Maneuver > &maneuvers, double max_starting_downtrack, const carma_wm::WorldModelConstPtr &wm, carma_planning_msgs::msg::VehicleState &ending_state_before_buffer, const carma_planning_msgs::msg::VehicleState &state, const GeneralTrajConfig &general_config, const DetailedTrajConfig &detailed_config)
 Creates geometry profile to return a point speed pair struct for LANE FOLLOW and LANE CHANGE maneuver types. More...
 
std::vector< PointSpeedPaircreate_lanefollow_geometry (const carma_planning_msgs::msg::Maneuver &maneuver, double max_starting_downtrack, const carma_wm::WorldModelConstPtr &wm, const GeneralTrajConfig &general_config, const DetailedTrajConfig &detailed_config, std::unordered_set< lanelet::Id > &visited_lanelets)
 Converts a set of requested LANE_FOLLOWING maneuvers to point speed limit pairs. More...
 
std::vector< PointSpeedPairadd_lanefollow_buffer (const carma_wm::WorldModelConstPtr &wm, std::vector< PointSpeedPair > &points_and_target_speeds, const std::vector< carma_planning_msgs::msg::Maneuver > &maneuvers, carma_planning_msgs::msg::VehicleState &ending_state_before_buffer, const DetailedTrajConfig &detailed_config)
 Adds extra centerline points beyond required message length to lane follow maneuver points so that there's always enough points to calculate trajectory (BUFFER POINTS SHOULD BE REMOVED BEFORE RETURNING FINAL TRAJECTORY) More...
 
std::vector< carma_planning_msgs::msg::TrajectoryPlanPoint > compose_lanefollow_trajectory_from_path (const std::vector< PointSpeedPair > &points, const carma_planning_msgs::msg::VehicleState &state, const rclcpp::Time &state_time, const carma_wm::WorldModelConstPtr &wm, const carma_planning_msgs::msg::VehicleState &ending_state_before_buffer, carma_debug_ros2_msgs::msg::TrajectoryCurvatureSpeeds &debug_msg, const DetailedTrajConfig &detailed_config)
 Method converts a list of lanelet centerline points and current vehicle state into a usable list of trajectory points for trajectory planning for a Lane following maneuver. More...
 
std::vector< PointSpeedPairget_lanechange_points_from_maneuver (const carma_planning_msgs::msg::Maneuver &maneuver, double max_starting_downtrack, const carma_wm::WorldModelConstPtr &wm, carma_planning_msgs::msg::VehicleState &ending_state_before_buffer, const carma_planning_msgs::msg::VehicleState &state, const GeneralTrajConfig &general_config, const DetailedTrajConfig &detailed_config)
 Converts a set of requested LANE_CHANGE maneuvers to point speed limit pairs. More...
 
std::vector< lanelet::BasicPoint2d > create_lanechange_geometry (lanelet::Id starting_lane_id, lanelet::Id ending_lane_id, double starting_downtrack, double ending_downtrack, const carma_wm::WorldModelConstPtr &wm, int downsample_ratio, double buffer_ending_downtrack)
 Creates a vector of lane change points using parameters defined. More...
 
std::vector< std::vector< lanelet::BasicPoint2d > > resample_linestring_pair_to_same_size (std::vector< lanelet::BasicPoint2d > &line_1, std::vector< lanelet::BasicPoint2d > &line_2)
 Resamples a pair of basicpoint2d lines to get lines of same number of points. More...
 
std::vector< carma_planning_msgs::msg::TrajectoryPlanPoint > compose_lanechange_trajectory_from_path (const std::vector< PointSpeedPair > &points, const carma_planning_msgs::msg::VehicleState &state, const rclcpp::Time &state_time, const carma_wm::WorldModelConstPtr &wm, const carma_planning_msgs::msg::VehicleState &ending_state_before_buffer, const DetailedTrajConfig &detailed_config)
 Method converts a list of lanelet centerline points and current vehicle state into a usable list of trajectory points for trajectory planning for a Lane following maneuver. More...
 
std::vector< lanelet::BasicPoint2d > create_route_geom (double starting_downtrack, int starting_lane_id, double ending_downtrack, const carma_wm::WorldModelConstPtr &wm)
 Creates a Lanelet2 Linestring from a vector or points along the geometry. More...
 
lanelet::BasicLineString2d create_lanechange_path (const lanelet::ConstLanelet &start_lanelet, const lanelet::ConstLanelet &end_lanelet)
 Given a start and end point, create a vector of points fit through a spline between the points (using a Spline library) More...
 
DetailedTrajConfig compose_detailed_trajectory_config (double trajectory_time_length, double curve_resample_step_size, double minimum_speed, double max_accel, double lateral_accel_limit, int speed_moving_average_window_size, int curvature_moving_average_window_size, double back_distance, double buffer_ending_downtrack, std::string desired_controller_plugin="default")
 
GeneralTrajConfig compose_general_trajectory_config (const std::string &trajectory_type, int default_downsample_ratio, int turn_downsample_ratio)
 
autoware_auto_msgs::msg::Trajectory process_trajectory_plan (const carma_planning_msgs::msg::TrajectoryPlan &tp, double vehicle_response_lag)
 Given a carma type of trajectory_plan, generate autoware type of trajectory accounting for speed_lag and stopping case Generated trajectory is meant to be used in autoware.auto's pure_pursuit library using set_trajectory() function. More...
 
std::vector< double > apply_response_lag (const std::vector< double > &speeds, const std::vector< double > downtracks, double response_lag)
 Applies a specified response lag in seconds to the trajectory shifting the whole thing by the specified lag time. More...
 
carma_planning_msgs::srv::PlanTrajectory::Response::SharedPtr modify_trajectory_to_yield_to_obstacles (const std::shared_ptr< carma_ros2_utils::CarmaLifecycleNode > &node_handler, const carma_planning_msgs::srv::PlanTrajectory::Request::SharedPtr &req, const carma_planning_msgs::srv::PlanTrajectory::Response::SharedPtr &resp, const carma_ros2_utils::ClientPtr< carma_planning_msgs::srv::PlanTrajectory > &yield_client, int yield_plugin_service_call_timeout)
 Applies a yield trajectory to the original trajectory set in response. More...
 
bool is_valid_yield_plan (const std::shared_ptr< carma_ros2_utils::CarmaLifecycleNode > &node_handler, const carma_planning_msgs::msg::TrajectoryPlan &yield_plan)
 Helper function to verify if the input yield trajectory plan is valid. More...
 
int get_nearest_point_index (const std::vector< lanelet::BasicPoint2d > &points, const carma_planning_msgs::msg::VehicleState &state)
 Returns the nearest point (in terms of cartesian 2d distance) to the provided vehicle pose in the provided l. More...
 
int get_nearest_point_index (const std::vector< PointSpeedPair > &points, const carma_planning_msgs::msg::VehicleState &state)
 Returns the nearest point (in terms of cartesian 2d distance) to the provided vehicle pose in the provided list. More...
 
int get_nearest_index_by_downtrack (const std::vector< lanelet::BasicPoint2d > &points, const carma_wm::WorldModelConstPtr &wm, double target_downtrack)
 Returns the nearest "less than" point to the provided vehicle pose in the provided list by utilizing the downtrack measured along the route NOTE: This function compares the downtrack, provided by routeTrackPos, of each points in the list to get the closest one to the given point's downtrack. Therefore, it is rather costlier method than comparing cartesian distance between the points and getting the closest. This way, however, the function correctly returns the end point's index if the given state, despite being valid, is farther than the given points and can technically be near any of them. More...
 
void split_point_speed_pairs (const std::vector< PointSpeedPair > &points, std::vector< lanelet::BasicPoint2d > *basic_points, std::vector< double > *speeds)
 Helper method to split a list of PointSpeedPair into separate point and speed lists. More...
 
int get_nearest_index_by_downtrack (const std::vector< PointSpeedPair > &points, const carma_wm::WorldModelConstPtr &wm, const carma_planning_msgs::msg::VehicleState &state)
 Overload: Returns the nearest point to the provided vehicle pose in the provided list by utilizing the downtrack measured along the route NOTE: This function compares the downtrack, provided by routeTrackPos, of each points in the list to get the closest one to the given point's downtrack. Therefore, it is rather costlier method than comparing cartesian distance between the points and getting the closest. This way, however, the function correctly returns the end point's index if the given state, despite being valid, is farther than the given points and can technically be near any of them. More...
 
int get_nearest_index_by_downtrack (const std::vector< lanelet::BasicPoint2d > &points, const carma_wm::WorldModelConstPtr &wm, const carma_planning_msgs::msg::VehicleState &state)
 Overload: Returns the nearest point to the provided vehicle pose in the provided list by utilizing the downtrack measured along the route NOTE: This function compares the downtrack, provided by routeTrackPos, of each points in the list to get the closest one to the given point's downtrack. Therefore, it is rather costlier method than comparing cartesian distance between the points and getting the closest. This way, however, the function correctly returns the end point if the given state, despite being valid, is farther than the given points and can technically be near any of them. More...
 

Variables

static const std::string BASIC_AUTONOMY_LOGGER = "basic_autonomy"
 
const double epsilon_ = 0.0000001
 

Function Documentation

◆ add_lanefollow_buffer()

std::vector< PointSpeedPair > basic_autonomy::waypoint_generation::add_lanefollow_buffer ( const carma_wm::WorldModelConstPtr wm,
std::vector< PointSpeedPair > &  points_and_target_speeds,
const std::vector< carma_planning_msgs::msg::Maneuver > &  maneuvers,
carma_planning_msgs::msg::VehicleState &  ending_state_before_buffer,
const DetailedTrajConfig detailed_config 
)

Adds extra centerline points beyond required message length to lane follow maneuver points so that there's always enough points to calculate trajectory (BUFFER POINTS SHOULD BE REMOVED BEFORE RETURNING FINAL TRAJECTORY)

Parameters
wmPointer to intialized world model for semantic map access
points_and_target_speedsset of lane follow maneuver points to which buffer is added
maneuversThe list of lane follow maneuvers which were converted to geometry points and associated speed
ending_state_before_bufferreference to Vehicle state, which is state before applying extra points for curvature calculation that are removed later
detailed_configBasic autonomy struct defined to load detailed config parameters from tactical plugins
Returns
List of centerline points paired with speed limits returned with added buffer

Definition at line 225 of file basic_autonomy.cpp.

226 {
227
228
229 double starting_route_downtrack = wm->routeTrackPos(points_and_target_speeds.front().point).downtrack;
230
231 // Always try to add the maximum buffer. Even if the route ends it may still be possible to add buffered points.
232 // This does mean that downstream components might not be able to assume the buffer points are on the route
233 // though this is not likely to be an issue as they are buffer only
234 double ending_downtrack = maneuvers.back().lane_following_maneuver.end_dist + detailed_config.buffer_ending_downtrack;
235
236 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Add lanefollow buffer: ending_downtrack: " << ending_downtrack << ", maneuvers.back().lane_following_maneuver.end_dist: " << maneuvers.back().lane_following_maneuver.end_dist <<
237 ", detailed_config.buffer_ending_downtrack: " << detailed_config.buffer_ending_downtrack);
238
239 size_t max_i = points_and_target_speeds.size() - 1;
240 size_t unbuffered_idx = points_and_target_speeds.size() - 1;
241 bool found_unbuffered_idx = false;
242 double dist_accumulator = starting_route_downtrack;
243 lanelet::BasicPoint2d prev_point;
244
245 boost::optional<lanelet::BasicPoint2d> delta_point;
246 for (size_t i = 0; i < points_and_target_speeds.size(); ++i) {
247 auto current_point = points_and_target_speeds[i].point;
248
249 if (i == 0) {
250 prev_point = current_point;
251 continue;
252 }
253
254 double delta_d = lanelet::geometry::distance2d(prev_point, current_point);
255
256 dist_accumulator += delta_d;
257 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Index i: " << i << ", delta_d: " << delta_d << ", dist_accumulator:" << dist_accumulator <<", current_point.x():" << current_point.x() <<
258 "current_point.y():" << current_point.y());
259 if (dist_accumulator > maneuvers.back().lane_following_maneuver.end_dist && !found_unbuffered_idx)
260 {
261 unbuffered_idx = i - 1;
262 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Found index unbuffered_idx at: " << unbuffered_idx);
263 found_unbuffered_idx = true;
264 }
265
266 if (dist_accumulator > ending_downtrack) {
267 max_i = i;
268 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Max_i breaking at: i: " << i << ", max_i: " << max_i);
269 break;
270 }
271
272 // If there are no more points to add but we haven't reached the ending downtrack then
273 // construct an extrapolated straight line from the final point and keep adding to this line until the downtrack is met
274 // Since this is purely needed to allow for a spline fit edge case, it should have minimal impact on the actual steering behavior of the vehicle
275 if (i == points_and_target_speeds.size() - 1) // dist_accumulator < ending_downtrack is guaranteed by earlier conditional
276 {
277
278 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Extending trajectory using buffer beyond end of target lanelet");
279 int j = i - 1;
280 while (delta_d < epsilon_ && j >= 0 && !delta_point)
281 {
282 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Looking at index j: " << j << ", where i: " << i);
283 prev_point = points_and_target_speeds.at(j).point;
284 j--;
285 delta_d = lanelet::geometry::distance2d(prev_point, current_point);
286 }
287
288 if (j < 0 && delta_d < epsilon_) //a very rare case where only duplicate points exist in the entire trajectory, so it wasn't possible to extend
289 break;
290
291 if (!delta_point) { // Set the step size based on last two distinct points
292 delta_point = (current_point - prev_point) * 0.25; // Use a smaller step size then default to help ensure enough points are generated;
293 }
294
295 // Create an extrapolated new point
296 auto new_point = current_point + delta_point.get();
297
298 PointSpeedPair new_pair;
299 new_pair.point = new_point;
300 new_pair.speed = points_and_target_speeds.back().speed;
301
302
303 points_and_target_speeds.push_back(new_pair);
304 }
305
306 prev_point = current_point;
307 }
308
309 ending_state_before_buffer.x_pos_global = points_and_target_speeds[unbuffered_idx].point.x();
310 ending_state_before_buffer.y_pos_global = points_and_target_speeds[unbuffered_idx].point.y();
311 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Here ending_state_before_buffer.x_pos_global: " << ending_state_before_buffer.x_pos_global <<
312 ", and y_pos_global" << ending_state_before_buffer.y_pos_global);
313
314 std::vector<PointSpeedPair> constrained_points(points_and_target_speeds.begin(), points_and_target_speeds.begin() + max_i);
315
316 return constrained_points;
317 }
static const std::string BASIC_AUTONOMY_LOGGER
basic_autonomy::waypoint_generation::PointSpeedPair PointSpeedPair

References BASIC_AUTONOMY_LOGGER, basic_autonomy::waypoint_generation::DetailedTrajConfig::buffer_ending_downtrack, epsilon_, process_bag::i, basic_autonomy::waypoint_generation::PointSpeedPair::point, and basic_autonomy::waypoint_generation::PointSpeedPair::speed.

Referenced by create_geometry_profile(), and light_controlled_intersection_tactical_plugin::LightControlledIntersectionTacticalPlugin::createGeometryProfile().

Here is the caller graph for this function:

◆ apply_response_lag()

std::vector< double > basic_autonomy::waypoint_generation::apply_response_lag ( const std::vector< double > &  speeds,
const std::vector< double >  downtracks,
double  response_lag 
)

Applies a specified response lag in seconds to the trajectory shifting the whole thing by the specified lag time.

Parameters
speedsVelocity profile to shift. The first point should be the current vehicle speed
downtrackDistance points for each velocity point. Should have the same size as speeds and start from 0
response_lagThe lag in seconds before which the vehicle will not meaningfully accelerate
Returns
A Shifted trajectory

Definition at line 1297 of file basic_autonomy.cpp.

1298 { // Note first speed is assumed to be vehicle speed
1299 if (speeds.size() != downtracks.size()) {
1300 throw std::invalid_argument("Speed list and downtrack list are not the same size.");
1301 }
1302
1303 std::vector<double> output;
1304 if (speeds.empty()) {
1305 return output;
1306 }
1307
1308 double lookahead_distance = speeds[0] * response_lag;
1309
1310 double downtrack_cutoff = downtracks[0] + lookahead_distance;
1311 size_t lookahead_count = std::lower_bound(downtracks.begin(),downtracks.end(), downtrack_cutoff) - downtracks.begin(); // Use binary search to find lower bound cutoff point
1312 output = trajectory_utils::shift_by_lookahead(speeds, (unsigned int) lookahead_count);
1313 return output;
1314 }

Referenced by process_trajectory_plan().

Here is the caller graph for this function:

◆ apply_speed_limits()

std::vector< double > basic_autonomy::waypoint_generation::apply_speed_limits ( const std::vector< double >  speeds,
const std::vector< double >  speed_limits 
)

Applies the provided speed limits to the provided speeds such that each element is capped at its corresponding speed limit if needed.

Parameters
speedsThe speeds to limit
speed_limitsThe speed limits to apply. Must have the same size as speeds
Returns
The capped speed limits. Has the same size as speeds

Definition at line 616 of file basic_autonomy.cpp.

618 {
619 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Speeds list size: " << speeds.size());
620 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "SpeedLimits list size: " << speed_limits.size());
621
622 if (speeds.size() != speed_limits.size())
623 {
624 throw std::invalid_argument("Speeds and speed limit lists not same size");
625 }
626 std::vector<double> out;
627 for (size_t i = 0; i < speeds.size(); i++)
628 {
629 out.push_back(std::min(speeds[i], speed_limits[i]));
630 }
631
632 return out;
633 }

References BASIC_AUTONOMY_LOGGER, and process_bag::i.

Referenced by compose_lanefollow_trajectory_from_path(), and stop_controlled_intersection_tactical_plugin::StopControlledIntersectionTacticalPlugin::compose_trajectory_from_centerline().

Here is the caller graph for this function:

◆ attach_past_points()

std::vector< PointSpeedPair > basic_autonomy::waypoint_generation::attach_past_points ( const std::vector< PointSpeedPair > &  points_set,
std::vector< PointSpeedPair future_points,
const int  nearest_pt_index,
double  back_distance 
)

Attaches back_distance length of points behind the future points.

Parameters
points_setall point speed pairs
future_pointsfuture points before which to attach the points
nearest_pt_indexidx of the first future_point in points_set
back_distancethe back distance to be added, in meters
Returns
point speed pairs with back distance length of points in front of future points NOTE- used to add past points to future trajectory for smooth spline calculation

Definition at line 793 of file basic_autonomy.cpp.

795 {
796 std::vector<PointSpeedPair> back_and_future;
797 back_and_future.reserve(points_set.size());
798 double total_dist = 0;
799 int min_i = 0;
800
801 // int must be used here to avoid overflow when i = 0
802 for (int i = nearest_pt_index; i >= 0; --i)
803 {
804 min_i = i;
805 total_dist += lanelet::geometry::distance2d(points_set[i].point, points_set[i - 1].point);
806
807 if (total_dist > back_distance)
808 {
809 break;
810 }
811 }
812
813 back_and_future.insert(back_and_future.end(), points_set.begin() + min_i, points_set.begin() + nearest_pt_index + 1);
814 back_and_future.insert(back_and_future.end(), future_points.begin(), future_points.end());
815 return back_and_future;
816 }

References process_bag::i, and process_traj_logs::point.

Referenced by compose_lanefollow_trajectory_from_path(), and stop_controlled_intersection_tactical_plugin::StopControlledIntersectionTacticalPlugin::compose_trajectory_from_centerline().

Here is the caller graph for this function:

◆ compose_detailed_trajectory_config()

DetailedTrajConfig basic_autonomy::waypoint_generation::compose_detailed_trajectory_config ( double  trajectory_time_length,
double  curve_resample_step_size,
double  minimum_speed,
double  max_accel,
double  lateral_accel_limit,
int  speed_moving_average_window_size,
int  curvature_moving_average_window_size,
double  back_distance,
double  buffer_ending_downtrack,
std::string  desired_controller_plugin = "default" 
)

Definition at line 1082 of file basic_autonomy.cpp.

1092 {
1093 DetailedTrajConfig detailed_config;
1094
1095 detailed_config.trajectory_time_length = trajectory_time_length;
1096 detailed_config.curve_resample_step_size = curve_resample_step_size;
1097 detailed_config.minimum_speed = minimum_speed;
1098 detailed_config.max_accel = max_accel;
1099 detailed_config.lateral_accel_limit = lateral_accel_limit;
1100 detailed_config.speed_moving_average_window_size = speed_moving_average_window_size;
1101 detailed_config.curvature_moving_average_window_size = curvature_moving_average_window_size;
1102 detailed_config.back_distance = back_distance;
1103 detailed_config.buffer_ending_downtrack = buffer_ending_downtrack;
1104 detailed_config.desired_controller_plugin = desired_controller_plugin;
1105
1106 return detailed_config;
1107 }

References basic_autonomy::waypoint_generation::DetailedTrajConfig::back_distance, basic_autonomy::waypoint_generation::DetailedTrajConfig::buffer_ending_downtrack, basic_autonomy::waypoint_generation::DetailedTrajConfig::curvature_moving_average_window_size, basic_autonomy::waypoint_generation::DetailedTrajConfig::curve_resample_step_size, basic_autonomy::waypoint_generation::DetailedTrajConfig::desired_controller_plugin, basic_autonomy::waypoint_generation::DetailedTrajConfig::lateral_accel_limit, basic_autonomy::waypoint_generation::DetailedTrajConfig::max_accel, basic_autonomy::waypoint_generation::DetailedTrajConfig::minimum_speed, basic_autonomy::waypoint_generation::DetailedTrajConfig::speed_moving_average_window_size, and basic_autonomy::waypoint_generation::DetailedTrajConfig::trajectory_time_length.

Referenced by cooperative_lanechange::CooperativeLaneChangePlugin::plan_lanechange(), inlanecruising_plugin::InLaneCruisingPlugin::plan_trajectory_callback(), platooning_tactical_plugin::PlatooningTacticalPlugin::plan_trajectory_cb(), and light_controlled_intersection_tactical_plugin::LightControlledIntersectionTacticalPlugin::planTrajectoryCB().

Here is the caller graph for this function:

◆ compose_general_trajectory_config()

GeneralTrajConfig basic_autonomy::waypoint_generation::compose_general_trajectory_config ( const std::string &  trajectory_type,
int  default_downsample_ratio,
int  turn_downsample_ratio 
)

◆ compose_lanechange_trajectory_from_path()

std::vector< carma_planning_msgs::msg::TrajectoryPlanPoint > basic_autonomy::waypoint_generation::compose_lanechange_trajectory_from_path ( const std::vector< PointSpeedPair > &  points,
const carma_planning_msgs::msg::VehicleState &  state,
const rclcpp::Time &  state_time,
const carma_wm::WorldModelConstPtr wm,
const carma_planning_msgs::msg::VehicleState &  ending_state_before_buffer,
const DetailedTrajConfig detailed_config 
)

Method converts a list of lanelet centerline points and current vehicle state into a usable list of trajectory points for trajectory planning for a Lane following maneuver.

Parameters
pointsThe set of points that define the current lane the vehicle is in and are defined based on the request planning maneuvers. These points must be in the same lane as the vehicle and must extend in front of it though it is fine if they also extend behind it.
stateThe current state of the vehicle
state_timeThe abosolute time which the provided vehicle state corresponds to
wmThe carma world model object which the vehicle is operating in.
ending_state_before_bufferThe vehicle state before a buffer was added to the points. Used to revert the trajectory to required distance before returning.
Returns
A list of trajectory points to send to the carma planning stack

Definition at line 1124 of file basic_autonomy.cpp.

1127 {
1128 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Input points size in compose traj from centerline: "<< points.size());
1129 int nearest_pt_index = get_nearest_index_by_downtrack(points, wm, state);
1130 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "nearest_pt_index: "<< nearest_pt_index);
1131
1132 std::vector<PointSpeedPair> future_points(points.begin() + nearest_pt_index + 1, points.end());
1133 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "future_points size: "<< future_points.size());
1134
1135 //Compute yaw values from original trajectory.
1136 std::vector<lanelet::BasicPoint2d> future_geom_points;
1137 std::vector<double> final_actual_speeds;
1138 split_point_speed_pairs(future_points, &future_geom_points, &final_actual_speeds);
1139
1140 std::unique_ptr<smoothing::SplineI> fit_curve = compute_fit(future_geom_points);
1141 if(!fit_curve){
1142 throw std::invalid_argument("Could not fit a spline curve along the given trajectory!");
1143 }
1144 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Got fit");
1145 std::vector<lanelet::BasicPoint2d> all_sampling_points;
1146 all_sampling_points.reserve(1 + future_geom_points.size() * 2);
1147
1148 lanelet::BasicPoint2d current_vehicle_point(state.x_pos_global, state.y_pos_global);
1149
1150 future_geom_points.insert(future_geom_points.begin(),
1151 current_vehicle_point); // Add current vehicle position to front of future geometry points
1152
1153 final_actual_speeds.insert(final_actual_speeds.begin(), state.longitudinal_vel);
1154
1155 //Compute points to local downtracks
1156 std::vector<double> downtracks = carma_wm::geometry::compute_arc_lengths(future_geom_points);
1157
1158 auto total_step_along_curve = static_cast<int>(downtracks.back() /detailed_config.curve_resample_step_size);
1159
1160 double scaled_steps_along_curve = 0.0; //from 0 (start) to 1 (end) for the whole trajectory
1161
1162 for(int steps_along_curve = 0; steps_along_curve < total_step_along_curve; steps_along_curve++){
1163 lanelet::BasicPoint2d p = (*fit_curve)(scaled_steps_along_curve);
1164
1165 all_sampling_points.push_back(p);
1166
1167 scaled_steps_along_curve += 1.0 / total_step_along_curve;
1168 }
1169 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Got sampled points with size:" << all_sampling_points.size());
1170
1171 std::vector<double> final_yaw_values = carma_wm::geometry::compute_tangent_orientations(future_geom_points);
1172 if(final_yaw_values.size() > 0) {
1173 final_yaw_values[0] = state.orientation; // Set the initial yaw value based on the initial state
1174 }
1175
1176 final_actual_speeds = smoothing::moving_average_filter(final_actual_speeds, detailed_config.speed_moving_average_window_size);
1177
1178 //Convert speeds to time
1179 std::vector<double> times;
1180 trajectory_utils::conversions::speed_to_time(downtracks, final_actual_speeds, &times);
1181
1182 //Remove extra points
1183 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Before removing extra buffer points, future_geom_points.size()"<< future_geom_points.size());
1184 int end_dist_pt_index = get_nearest_index_by_downtrack(future_geom_points, wm, ending_state_before_buffer);
1185 future_geom_points.resize(end_dist_pt_index + 1);
1186 times.resize(end_dist_pt_index + 1);
1187 final_yaw_values.resize(end_dist_pt_index + 1);
1188 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "After removing extra buffer points, future_geom_points.size():"<< future_geom_points.size());
1189
1190 std::vector<carma_planning_msgs::msg::TrajectoryPlanPoint> traj_points =
1191 trajectory_from_points_times_orientations(future_geom_points, times, final_yaw_values, state_time, detailed_config.desired_controller_plugin);
1192
1193 return traj_points;
1194 }
std::vector< double > moving_average_filter(const std::vector< double > input, int window_size, bool ignore_first_point=true)
Extremely simplie moving average filter.
Definition: filters.cpp:24
void split_point_speed_pairs(const std::vector< PointSpeedPair > &points, std::vector< lanelet::BasicPoint2d > *basic_points, std::vector< double > *speeds)
Helper method to split a list of PointSpeedPair into separate point and speed lists.
std::unique_ptr< basic_autonomy::smoothing::SplineI > compute_fit(const std::vector< lanelet::BasicPoint2d > &basic_points)
Computes a spline based on the provided points.
int get_nearest_index_by_downtrack(const std::vector< lanelet::BasicPoint2d > &points, const carma_wm::WorldModelConstPtr &wm, double target_downtrack)
Returns the nearest "less than" point to the provided vehicle pose in the provided list by utilizing ...
std::vector< carma_planning_msgs::msg::TrajectoryPlanPoint > trajectory_from_points_times_orientations(const std::vector< lanelet::BasicPoint2d > &points, const std::vector< double > &times, const std::vector< double > &yaws, rclcpp::Time startTime, const std::string &desired_controller_plugin)
Method combines input points, times, orientations, and an absolute start time to form a valid carma p...
std::vector< double > compute_tangent_orientations(const lanelet::BasicLineString2d &centerline)
Compute an approximate orientation for the vehicle at each point along the provided centerline.
Definition: Geometry.cpp:559
std::vector< double > compute_arc_lengths(const std::vector< lanelet::BasicPoint2d > &data)
Compute the arc length at each point around the curve.
Definition: Geometry.cpp:498

References BASIC_AUTONOMY_LOGGER, carma_wm::geometry::compute_arc_lengths(), compute_fit(), carma_wm::geometry::compute_tangent_orientations(), basic_autonomy::waypoint_generation::DetailedTrajConfig::curve_resample_step_size, basic_autonomy::waypoint_generation::DetailedTrajConfig::desired_controller_plugin, get_nearest_index_by_downtrack(), basic_autonomy::smoothing::moving_average_filter(), basic_autonomy::waypoint_generation::DetailedTrajConfig::speed_moving_average_window_size, split_point_speed_pairs(), and trajectory_from_points_times_orientations().

Referenced by cooperative_lanechange::CooperativeLaneChangePlugin::plan_lanechange().

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

◆ compose_lanefollow_trajectory_from_path()

std::vector< carma_planning_msgs::msg::TrajectoryPlanPoint > basic_autonomy::waypoint_generation::compose_lanefollow_trajectory_from_path ( const std::vector< PointSpeedPair > &  points,
const carma_planning_msgs::msg::VehicleState &  state,
const rclcpp::Time &  state_time,
const carma_wm::WorldModelConstPtr wm,
const carma_planning_msgs::msg::VehicleState &  ending_state_before_buffer,
carma_debug_ros2_msgs::msg::TrajectoryCurvatureSpeeds &  debug_msg,
const DetailedTrajConfig detailed_config 
)

Method converts a list of lanelet centerline points and current vehicle state into a usable list of trajectory points for trajectory planning for a Lane following maneuver.

Parameters
pointsThe set of points that define the current lane the vehicle is in and are defined based on the request planning maneuvers. These points must be in the same lane as the vehicle and must extend in front of it though it is fine if they also extend behind it.
stateThe current state of the vehicle
state_timeThe abosolute time which the provided vehicle state corresponds to
Returns
A list of trajectory points to send to the carma planning stack

Definition at line 865 of file basic_autonomy.cpp.

868 {
869 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "VehicleState: "
870 << " x: " << state.x_pos_global << " y: " << state.y_pos_global << " yaw: " << state.orientation
871 << " speed: " << state.longitudinal_vel);
872
874
875 int nearest_pt_index = get_nearest_point_index(points, state);
876
877 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "NearestPtIndex: " << nearest_pt_index);
878
879 std::vector<PointSpeedPair> future_points(points.begin() + nearest_pt_index + 1, points.end()); // Points in front of current vehicle position
880
881 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Ready to call constrain_to_time_boundary: future_points size = " << future_points.size() << ", trajectory_time_length = " << detailed_config.trajectory_time_length);
882
883 auto time_bound_points = constrain_to_time_boundary(future_points, detailed_config.trajectory_time_length);
884
885 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Got time_bound_points with size:" << time_bound_points.size());
887
888 std::vector<PointSpeedPair> back_and_future = attach_past_points(points, time_bound_points, nearest_pt_index, detailed_config.back_distance);
889
890 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Got back_and_future points with size" << back_and_future.size());
892
893 std::vector<double> speed_limits;
894 std::vector<lanelet::BasicPoint2d> curve_points;
895 split_point_speed_pairs(back_and_future, &curve_points, &speed_limits);
896
897 std::unique_ptr<smoothing::SplineI> fit_curve = compute_fit(curve_points); // Compute splines based on curve points
898 if (!fit_curve)
899 {
900 throw std::invalid_argument("Could not fit a spline curve along the given trajectory!");
901 }
902
903 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Got fit");
904
905 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "speed_limits.size() " << speed_limits.size());
906
907 std::vector<lanelet::BasicPoint2d> all_sampling_points;
908 all_sampling_points.reserve(1 + curve_points.size() * 2);
909
910 std::vector<double> distributed_speed_limits;
911 distributed_speed_limits.reserve(1 + curve_points.size() * 2);
912
913 // compute total length of the trajectory to get correct number of points
914 // we expect using curve_resample_step_size
915 std::vector<double> downtracks_raw = carma_wm::geometry::compute_arc_lengths(curve_points);
916
917 auto total_step_along_curve = static_cast<int>(downtracks_raw.back() / detailed_config.curve_resample_step_size);
918
919 int current_speed_index = 0;
920 size_t total_point_size = curve_points.size();
921
922 double step_threshold_for_next_speed = (double)total_step_along_curve / (double)total_point_size;
923 double scaled_steps_along_curve = 0.0; // from 0 (start) to 1 (end) for the whole trajectory
924 std::vector<double> better_curvature;
925 better_curvature.reserve(1 + curve_points.size() * 2);
926
927 for (int steps_along_curve = 0; steps_along_curve < total_step_along_curve; steps_along_curve++) // Resample curve at tighter resolution
928 {
929 lanelet::BasicPoint2d p = (*fit_curve)(scaled_steps_along_curve);
930
931 all_sampling_points.push_back(p);
932 double c = compute_curvature_at((*fit_curve), scaled_steps_along_curve);
933 better_curvature.push_back(c);
934 if ((double)steps_along_curve > step_threshold_for_next_speed)
935 {
936 step_threshold_for_next_speed += (double)total_step_along_curve / (double)total_point_size;
937 current_speed_index++;
938 }
939 distributed_speed_limits.push_back(speed_limits[current_speed_index]); // Identify speed limits for resampled points
940 scaled_steps_along_curve += 1.0 / total_step_along_curve; //adding steps_along_curve_step_size
941 }
942
943 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Got sampled points with size:" << all_sampling_points.size());
944 log::printDebugPerLine(all_sampling_points, &log::basicPointToStream);
945
946 std::vector<double> final_yaw_values = carma_wm::geometry::compute_tangent_orientations(all_sampling_points);
947
948 log::printDoublesPerLineWithPrefix("raw_curvatures[i]: ", better_curvature);
949
950 std::vector<double> curvatures = smoothing::moving_average_filter(better_curvature, detailed_config.curvature_moving_average_window_size, false);
951 std::vector<double> ideal_speeds =
952 trajectory_utils::constrained_speeds_for_curvatures(curvatures, detailed_config.lateral_accel_limit);
953
954 log::printDoublesPerLineWithPrefix("curvatures[i]: ", curvatures);
955 log::printDoublesPerLineWithPrefix("ideal_speeds: ", ideal_speeds);
956 log::printDoublesPerLineWithPrefix("final_yaw_values[i]: ", final_yaw_values);
957
958 std::vector<double> constrained_speed_limits = apply_speed_limits(ideal_speeds, distributed_speed_limits);
959
960 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Processed all points in computed fit");
961
962 if (all_sampling_points.empty())
963 {
964 RCLCPP_WARN_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "No trajectory points could be generated");
965 return {};
966 }
967
968 // Add current vehicle point to front of the trajectory
969
970 nearest_pt_index = get_nearest_index_by_downtrack(all_sampling_points, wm, state);
971 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Current state's nearest_pt_index: " << nearest_pt_index);
972 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Curvature right now: " << better_curvature[nearest_pt_index] << ", at state x: " << state.x_pos_global << ", state y: " << state.y_pos_global);
973 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Corresponding to point: x: " << all_sampling_points[nearest_pt_index].x() << ", y:" << all_sampling_points[nearest_pt_index].y());
974
975 int buffer_pt_index = get_nearest_index_by_downtrack(all_sampling_points, wm, ending_state_before_buffer);
976 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Ending state's index before applying buffer (buffer_pt_index): " << buffer_pt_index);
977 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Corresponding to point: x: " << all_sampling_points[buffer_pt_index].x() << ", y:" << all_sampling_points[buffer_pt_index].y());
978
979 if(nearest_pt_index + 1 >= buffer_pt_index){
980
981 lanelet::BasicPoint2d current_pos(state.x_pos_global, state.y_pos_global);
982 lanelet::BasicPoint2d ending_pos(ending_state_before_buffer.x_pos_global, ending_state_before_buffer.y_pos_global);
983
984 if(wm->routeTrackPos(ending_pos).downtrack < wm->routeTrackPos(current_pos).downtrack ){
985
986 RCLCPP_WARN_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Current state is at or past the planned end distance. Couldn't generate trajectory");
987 return {};
988 }
989 else{
990 //Current point is behind the ending state of maneuver and a valid trajectory is possible
991 RCLCPP_WARN_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Returning the two remaining points in the maneuver");
992
993 std::vector<lanelet::BasicPoint2d> remaining_traj_points = {current_pos, ending_pos};
994
995 std::vector<double> downtracks = carma_wm::geometry::compute_arc_lengths(remaining_traj_points);
996 std::vector<double> speeds = {state.longitudinal_vel, state.longitudinal_vel};//Keep current speed
997 std::vector<double> times;
998 trajectory_utils::conversions::speed_to_time(downtracks, speeds, &times);
999 std::vector<double> yaw = {state.orientation, state.orientation}; //Keep current orientation
1000
1001 std::vector<carma_planning_msgs::msg::TrajectoryPlanPoint> traj_points =
1002 trajectory_from_points_times_orientations(remaining_traj_points, times, yaw, state_time, detailed_config.desired_controller_plugin);
1003
1004 return traj_points;
1005
1006 }
1007 }
1008
1009 //drop buffer points here
1010
1011 std::vector<lanelet::BasicPoint2d> future_basic_points(all_sampling_points.begin() + nearest_pt_index + 1,
1012 all_sampling_points.begin()+ buffer_pt_index); // Points in front of current vehicle position
1013
1014 std::vector<double> future_speeds(constrained_speed_limits.begin() + nearest_pt_index + 1,
1015 constrained_speed_limits.begin() + buffer_pt_index); // Points in front of current vehicle position
1016 std::vector<double> future_yaw(final_yaw_values.begin() + nearest_pt_index + 1,
1017 final_yaw_values.begin() + buffer_pt_index); // Points in front of current vehicle position
1018 std::vector<double> final_actual_speeds = future_speeds;
1019 all_sampling_points = future_basic_points;
1020 final_yaw_values = future_yaw;
1021 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Trimmed future points to size: "<< future_basic_points.size());
1022
1023 lanelet::BasicPoint2d cur_veh_point(state.x_pos_global, state.y_pos_global);
1024
1025 all_sampling_points.insert(all_sampling_points.begin(),
1026 cur_veh_point); // Add current vehicle position to front of sample points
1027
1028 final_actual_speeds.insert(final_actual_speeds.begin(), state.longitudinal_vel);
1029
1030 final_yaw_values.insert(final_yaw_values.begin(), state.orientation);
1031
1032 // Compute points to local downtracks
1033 std::vector<double> downtracks = carma_wm::geometry::compute_arc_lengths(all_sampling_points);
1034
1035 // Apply accel limits
1036 final_actual_speeds = optimize_speed(downtracks, final_actual_speeds, detailed_config.max_accel);
1037
1038 log::printDoublesPerLineWithPrefix("postAccel[i]: ", final_actual_speeds);
1039
1040 final_actual_speeds = smoothing::moving_average_filter(final_actual_speeds, detailed_config.speed_moving_average_window_size);
1041
1042 log::printDoublesPerLineWithPrefix("post_average[i]: ", final_actual_speeds);
1043
1044 for (auto &s : final_actual_speeds) // Limit minimum speed. TODO how to handle stopping?
1045 {
1046 s = std::max(s, detailed_config.minimum_speed);
1047 }
1048
1049 log::printDoublesPerLineWithPrefix("post_min_speed[i]: ", final_actual_speeds);
1050
1051 // Convert speeds to times
1052 std::vector<double> times;
1053 trajectory_utils::conversions::speed_to_time(downtracks, final_actual_speeds, &times);
1054
1055 log::printDoublesPerLineWithPrefix("times[i]: ", times);
1056
1057 // Build trajectory points
1058 std::vector<carma_planning_msgs::msg::TrajectoryPlanPoint> traj_points =
1059 trajectory_from_points_times_orientations(all_sampling_points, times, final_yaw_values, state_time, detailed_config.desired_controller_plugin);
1060
1061 //debug msg
1062 carma_debug_ros2_msgs::msg::TrajectoryCurvatureSpeeds msg;
1063 msg.velocity_profile = final_actual_speeds;
1064 msg.relative_downtrack = downtracks;
1065 msg.tangent_headings = final_yaw_values;
1066 std::vector<double> aligned_speed_limits(constrained_speed_limits.begin() + nearest_pt_index,
1067 constrained_speed_limits.end());
1068
1069 msg.speed_limits = aligned_speed_limits;
1070 std::vector<double> aligned_curvatures(curvatures.begin() + nearest_pt_index,
1071 curvatures.end());
1072 msg.curvatures = aligned_curvatures;
1073 msg.lat_accel_limit = detailed_config.lateral_accel_limit;
1074 msg.lon_accel_limit = detailed_config.max_accel;
1075 msg.starting_state = state;
1076 debug_msg = msg;
1077
1078
1079 return traj_points;
1080 }
void printDoublesPerLineWithPrefix(const std::string &prefix, const std::vector< double > &values)
Print a RCLCPP_DEBUG_STREAM for each value in values where the printed value is << prefix << value.
Definition: log.cpp:45
std::string basicPointToStream(lanelet::BasicPoint2d point)
Helper function to convert a lanelet::BasicPoint2d to a string.
Definition: log.cpp:26
std::string pointSpeedPairToStream(waypoint_generation::PointSpeedPair point)
Helper function to convert a PointSpeedPair to a string.
Definition: log.cpp:35
void printDebugPerLine(const std::vector< T > &values, std::function< std::string(T)> func)
Print a RCLCPP_DEBUG_STREAM for each value in values where the printed value is a string returned by ...
Definition: log.hpp:40
std::vector< double > optimize_speed(const std::vector< double > &downtracks, const std::vector< double > &curv_speeds, double accel_limit)
Applies the longitudinal acceleration limit to each point's speed.
int get_nearest_point_index(const std::vector< lanelet::BasicPoint2d > &points, const carma_planning_msgs::msg::VehicleState &state)
Returns the nearest point (in terms of cartesian 2d distance) to the provided vehicle pose in the pro...
std::vector< double > apply_speed_limits(const std::vector< double > speeds, const std::vector< double > speed_limits)
Applies the provided speed limits to the provided speeds such that each element is capped at its corr...
double compute_curvature_at(const basic_autonomy::smoothing::SplineI &fit_curve, double step_along_the_curve)
Given the curvature fit, computes the curvature at the given step along the curve.
std::vector< PointSpeedPair > constrain_to_time_boundary(const std::vector< PointSpeedPair > &points, double time_span)
Reduces the input points to only those points that fit within the provided time boundary.
std::vector< PointSpeedPair > attach_past_points(const std::vector< PointSpeedPair > &points_set, std::vector< PointSpeedPair > future_points, const int nearest_pt_index, double back_distance)
Attaches back_distance length of points behind the future points.

References apply_speed_limits(), attach_past_points(), basic_autonomy::waypoint_generation::DetailedTrajConfig::back_distance, BASIC_AUTONOMY_LOGGER, basic_autonomy::log::basicPointToStream(), process_traj_logs::c, carma_wm::geometry::compute_arc_lengths(), compute_curvature_at(), compute_fit(), carma_wm::geometry::compute_tangent_orientations(), constrain_to_time_boundary(), basic_autonomy::waypoint_generation::DetailedTrajConfig::curvature_moving_average_window_size, basic_autonomy::waypoint_generation::DetailedTrajConfig::curve_resample_step_size, basic_autonomy::waypoint_generation::DetailedTrajConfig::desired_controller_plugin, get_nearest_index_by_downtrack(), get_nearest_point_index(), basic_autonomy::waypoint_generation::DetailedTrajConfig::lateral_accel_limit, basic_autonomy::waypoint_generation::DetailedTrajConfig::max_accel, basic_autonomy::waypoint_generation::DetailedTrajConfig::minimum_speed, basic_autonomy::smoothing::moving_average_filter(), optimize_speed(), basic_autonomy::log::pointSpeedPairToStream(), basic_autonomy::log::printDebugPerLine(), basic_autonomy::log::printDoublesPerLineWithPrefix(), basic_autonomy::waypoint_generation::DetailedTrajConfig::speed_moving_average_window_size, split_point_speed_pairs(), trajectory_from_points_times_orientations(), basic_autonomy::waypoint_generation::DetailedTrajConfig::trajectory_time_length, process_traj_logs::x, and process_traj_logs::y.

Referenced by inlanecruising_plugin::InLaneCruisingPlugin::plan_trajectory_callback(), platooning_tactical_plugin::PlatooningTacticalPlugin::plan_trajectory_cb(), and light_controlled_intersection_tactical_plugin::LightControlledIntersectionTacticalPlugin::planTrajectoryCB().

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

◆ compute_curvature_at()

double basic_autonomy::waypoint_generation::compute_curvature_at ( const basic_autonomy::smoothing::SplineI fit_curve,
double  step_along_the_curve 
)

Given the curvature fit, computes the curvature at the given step along the curve.

Parameters
step_along_the_curveValue in double from 0.0 (curvature start) to 1.0 (curvature end) representing where to calculate the curvature
fit_curvecurvature fit
Returns
Curvature (k = 1/r, 1/meter)

Definition at line 855 of file basic_autonomy.cpp.

856 {
857 lanelet::BasicPoint2d f_prime_pt = fit_curve.first_deriv(step_along_the_curve);
858 lanelet::BasicPoint2d f_prime_prime_pt = fit_curve.second_deriv(step_along_the_curve);
859 // Convert to 3d vector to do 3d vector operations like cross.
860 Eigen::Vector3d f_prime = {f_prime_pt.x(), f_prime_pt.y(), 0};
861 Eigen::Vector3d f_prime_prime = {f_prime_prime_pt.x(), f_prime_prime_pt.y(), 0};
862 return (f_prime.cross(f_prime_prime)).norm() / (pow(f_prime.norm(), 3));
863 }
virtual lanelet::BasicPoint2d first_deriv(double x) const =0
Get the BasicPoint2d representing the first_deriv along the curve at t-th step.
virtual lanelet::BasicPoint2d second_deriv(double x) const =0
Get the BasicPoint2d representing the first_deriv along the curve at t-th step.

References basic_autonomy::smoothing::SplineI::first_deriv(), and basic_autonomy::smoothing::SplineI::second_deriv().

Referenced by compose_lanefollow_trajectory_from_path(), and stop_controlled_intersection_tactical_plugin::StopControlledIntersectionTacticalPlugin::compose_trajectory_from_centerline().

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

◆ compute_fit()

std::unique_ptr< basic_autonomy::smoothing::SplineI > basic_autonomy::waypoint_generation::compute_fit ( const std::vector< lanelet::BasicPoint2d > &  basic_points)

Computes a spline based on the provided points.

Parameters
basic_pointsThe points to use for fitting the spline
Returns
A spline which has been fit to the provided points

Definition at line 818 of file basic_autonomy.cpp.

819 {
820 if (basic_points.size() < 4)
821 {
822 RCLCPP_WARN_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Insufficient Spline Points");
823 return nullptr;
824 }
825
826 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Original basic_points size: " << basic_points.size());
827
828 std::vector<lanelet::BasicPoint2d> resized_basic_points = basic_points;
829
830 // The large the number of points, longer it takes to calculate a spline fit
831 // So if the basic_points vector size is large, only the first 400 points are used to compute a spline fit.
832 if (resized_basic_points.size() > 400)
833 {
834 resized_basic_points.resize(400);
835 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Resized basic_points size: " << resized_basic_points.size());
836
837 size_t left_points_size = basic_points.size() - resized_basic_points.size();
838 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Number of left out basic_points size: " << left_points_size);
839
840 float percent_points_lost = 100.0 * (float)left_points_size/basic_points.size();
841
842 if (percent_points_lost > 50.0)
843 {
844 RCLCPP_WARN_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "More than half of basic points are ignored for spline fitting");
845 }
846 }
847
848 std::unique_ptr<basic_autonomy::smoothing::SplineI> spl = std::make_unique<basic_autonomy::smoothing::BSpline>();
849
850 spl->setPoints(resized_basic_points);
851
852 return spl;
853 }

References BASIC_AUTONOMY_LOGGER.

Referenced by compose_lanechange_trajectory_from_path(), compose_lanefollow_trajectory_from_path(), stop_controlled_intersection_tactical_plugin::StopControlledIntersectionTacticalPlugin::compose_trajectory_from_centerline(), and resample_linestring_pair_to_same_size().

Here is the caller graph for this function:

◆ compute_heading_frame()

Eigen::Isometry2d basic_autonomy::waypoint_generation::compute_heading_frame ( const lanelet::BasicPoint2d &  p1,
const lanelet::BasicPoint2d &  p2 
)

Returns a 2D coordinate frame which is located at p1 and oriented so p2 lies on the +X axis.

Parameters
p1The origin point for the frame in the parent frame
p2A point in the parent frame that will define the +X axis relative to p1
Returns
A 2D coordinate frame transform

Definition at line 635 of file basic_autonomy.cpp.

637 {
638 Eigen::Rotation2Dd yaw(atan2(p2.y() - p1.y(), p2.x() - p1.x()));
639
641 }
Eigen::Isometry2d build2dEigenTransform(const Eigen::Vector2d &position, const Eigen::Rotation2Dd &rotation)
Builds a 2D Eigen coordinate frame transform with not applied scaling (only translation and rotation)...
Definition: Geometry.cpp:570

References carma_wm::geometry::build2dEigenTransform().

Here is the call graph for this function:

◆ constrain_to_time_boundary()

std::vector< PointSpeedPair > basic_autonomy::waypoint_generation::constrain_to_time_boundary ( const std::vector< PointSpeedPair > &  points,
double  time_span 
)

Reduces the input points to only those points that fit within the provided time boundary.

Parameters
pointsThe input point speed pairs to reduce
time_spanThe time span in seconds which the output points will fit within
Returns
The subset of points that fit within time_span

Definition at line 643 of file basic_autonomy.cpp.

645 {
646 std::vector<lanelet::BasicPoint2d> basic_points;
647 std::vector<double> speeds;
648 split_point_speed_pairs(points, &basic_points, &speeds);
649
650 std::vector<double> downtracks = carma_wm::geometry::compute_arc_lengths(basic_points);
651
652 size_t time_boundary_exclusive_index =
653 trajectory_utils::time_boundary_index(downtracks, speeds, time_span);
654
655 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "time_boundary_exclusive_index = " << time_boundary_exclusive_index);
656
657 if (time_boundary_exclusive_index == 0)
658 {
659 throw std::invalid_argument("No points to fit in timespan");
660 }
661
662 std::vector<PointSpeedPair> time_bound_points;
663 time_bound_points.reserve(time_boundary_exclusive_index);
664
665 if (time_boundary_exclusive_index == points.size())
666 {
667 time_bound_points.insert(time_bound_points.end(), points.begin(),
668 points.end()); // All points fit within time boundary
669 }
670 else
671 {
672 time_bound_points.insert(time_bound_points.end(), points.begin(),
673 points.begin() + time_boundary_exclusive_index - 1); // Limit points by time boundary
674 }
675
676 return time_bound_points;
677 }

References BASIC_AUTONOMY_LOGGER, carma_wm::geometry::compute_arc_lengths(), and split_point_speed_pairs().

Referenced by compose_lanefollow_trajectory_from_path(), and stop_controlled_intersection_tactical_plugin::StopControlledIntersectionTacticalPlugin::compose_trajectory_from_centerline().

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

◆ create_geometry_profile()

std::vector< PointSpeedPair > basic_autonomy::waypoint_generation::create_geometry_profile ( const std::vector< carma_planning_msgs::msg::Maneuver > &  maneuvers,
double  max_starting_downtrack,
const carma_wm::WorldModelConstPtr wm,
carma_planning_msgs::msg::VehicleState &  ending_state_before_buffer,
const carma_planning_msgs::msg::VehicleState &  state,
const GeneralTrajConfig general_config,
const DetailedTrajConfig detailed_config 
)

Creates geometry profile to return a point speed pair struct for LANE FOLLOW and LANE CHANGE maneuver types.

Parameters
maneuversThe list of maneuvers to convert to geometry points and calculate associated speed
max_starting_downtrackThe maximum downtrack that is allowed for the first maneuver. This should be set to the vehicle position or earlier. If the first maneuver exceeds this then it's downtrack will be shifted to this value.
wmPointer to intialized world model for semantic map access
ending_state_before_bufferreference to Vehicle state, which is state before applying extra points for curvature calculation that are removed later
stateThe vehicle state at the time the function is called
general_configBasic autonomy struct defined to load general config parameters from tactical plugins
detailed_configBasic autonomy struct defined to load detailed config parameters from tactical plugins
Returns
A vector of point speed pair struct which contains geometry points as basicpoint::lanelet2d and speed as a double for the maneuver

Definition at line 24 of file basic_autonomy.cpp.

26 {
27 std::vector<PointSpeedPair> points_and_target_speeds;
28
29 bool first = true;
30 std::unordered_set<lanelet::Id> visited_lanelets;
31
32 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "VehDowntrack:"<<max_starting_downtrack);
33 for(const auto &maneuver : maneuvers)
34 {
35 double starting_downtrack = GET_MANEUVER_PROPERTY(maneuver, start_dist);
36
37 if(first){
38 starting_downtrack = std::min(starting_downtrack, max_starting_downtrack);
39 first = false;
40 }
41 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Used downtrack: " << starting_downtrack);
42
43 if(maneuver.type == carma_planning_msgs::msg::Maneuver::LANE_FOLLOWING){
44 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER),"Creating Lane Follow Geometry");
45 std::vector<PointSpeedPair> lane_follow_points = create_lanefollow_geometry(maneuver, starting_downtrack, wm, general_config, detailed_config, visited_lanelets);
46 points_and_target_speeds.insert(points_and_target_speeds.end(), lane_follow_points.begin(), lane_follow_points.end());
47 }
48 else if(maneuver.type == carma_planning_msgs::msg::Maneuver::LANE_CHANGE){
49 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Creating Lane Change Geometry");
50 std::vector<PointSpeedPair> lane_change_points = get_lanechange_points_from_maneuver(maneuver, starting_downtrack, wm, ending_state_before_buffer, state, general_config, detailed_config);
51 points_and_target_speeds.insert(points_and_target_speeds.end(), lane_change_points.begin(), lane_change_points.end());
52 }
53 else{
54 throw std::invalid_argument("This maneuver type is not supported");
55 }
56
57 }
58
59 //Add buffer ending to lane follow points at the end of maneuver(s) end dist
60 if(maneuvers.back().type == carma_planning_msgs::msg::Maneuver::LANE_FOLLOWING){
61 points_and_target_speeds = add_lanefollow_buffer(wm, points_and_target_speeds, maneuvers, ending_state_before_buffer, detailed_config);
62
63 }
64 return points_and_target_speeds;
65
66 }
#define GET_MANEUVER_PROPERTY(mvr, property)
Macro definition to enable easier access to fields shared across the maneuver types.
std::vector< PointSpeedPair > create_lanefollow_geometry(const carma_planning_msgs::msg::Maneuver &maneuver, double max_starting_downtrack, const carma_wm::WorldModelConstPtr &wm, const GeneralTrajConfig &general_config, const DetailedTrajConfig &detailed_config, std::unordered_set< lanelet::Id > &visited_lanelets)
Converts a set of requested LANE_FOLLOWING maneuvers to point speed limit pairs.
std::vector< PointSpeedPair > add_lanefollow_buffer(const carma_wm::WorldModelConstPtr &wm, std::vector< PointSpeedPair > &points_and_target_speeds, const std::vector< carma_planning_msgs::msg::Maneuver > &maneuvers, carma_planning_msgs::msg::VehicleState &ending_state_before_buffer, const DetailedTrajConfig &detailed_config)
Adds extra centerline points beyond required message length to lane follow maneuver points so that th...
std::vector< PointSpeedPair > get_lanechange_points_from_maneuver(const carma_planning_msgs::msg::Maneuver &maneuver, double max_starting_downtrack, const carma_wm::WorldModelConstPtr &wm, carma_planning_msgs::msg::VehicleState &ending_state_before_buffer, const carma_planning_msgs::msg::VehicleState &state, const GeneralTrajConfig &general_config, const DetailedTrajConfig &detailed_config)
Converts a set of requested LANE_CHANGE maneuvers to point speed limit pairs.

References add_lanefollow_buffer(), BASIC_AUTONOMY_LOGGER, create_lanefollow_geometry(), get_lanechange_points_from_maneuver(), and GET_MANEUVER_PROPERTY.

Referenced by cooperative_lanechange::CooperativeLaneChangePlugin::plan_lanechange(), inlanecruising_plugin::InLaneCruisingPlugin::plan_trajectory_callback(), and platooning_tactical_plugin::PlatooningTacticalPlugin::plan_trajectory_cb().

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

◆ create_lanechange_geometry()

std::vector< lanelet::BasicPoint2d > basic_autonomy::waypoint_generation::create_lanechange_geometry ( lanelet::Id  starting_lane_id,
lanelet::Id  ending_lane_id,
double  starting_downtrack,
double  ending_downtrack,
const carma_wm::WorldModelConstPtr wm,
int  downsample_ratio,
double  buffer_ending_downtrack 
)

Creates a vector of lane change points using parameters defined.

Parameters
starting_lane_idlanelet id for where lane change plan should start
ending_lane_idlanelet id for where lane change plan should end
starting_downtrackThe downtrack distance from which the lane change maneuver starts
ending_downtrackThe downtrack distance at which the lane change maneuver end
wmPointer to intialized world model for semantic map access
downsample_ratioTODO: add description
buffer_ending_downtrackThe additional downtrack beyond requested end dist used to fit points along spline
Returns
A vector of geometry points as lanelet::basicpoint2d

Definition at line 319 of file basic_autonomy.cpp.

321 {
322 std::vector<lanelet::BasicPoint2d> centerline_points;
323
324 //Get starting lanelet and ending lanelets
325 lanelet::ConstLanelet starting_lanelet = wm->getMap()->laneletLayer.get(starting_lane_id);
326 lanelet::ConstLanelet ending_lanelet = wm->getMap()->laneletLayer.get(ending_lane_id);
327
328 lanelet::ConstLanelets starting_lane;
329 starting_lane.push_back(starting_lanelet);
330
331 std::vector<lanelet::BasicPoint2d> reference_centerline;
332 // 400 value here is an arbitrary attempt at improving performance by reducing copy operations.
333 // Value picked based on annecdotal evidence from STOL system testing
334 reference_centerline.reserve(400);
335 bool shared_boundary_found = false;
336 bool is_lanechange_left = false;
337
338 lanelet::BasicLineString2d current_lanelet_centerline = starting_lanelet.centerline2d().basicLineString();
339 lanelet::ConstLanelet current_lanelet = starting_lanelet;
340 reference_centerline.insert(reference_centerline.end(), current_lanelet_centerline.begin(), current_lanelet_centerline.end());
341
342 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Searching for shared boundary with starting lanechange lanelet " << std::to_string(current_lanelet.id()) << " and ending lanelet " << std::to_string(ending_lanelet.id()));
343 while(!shared_boundary_found){
344 //Assumption- Adjacent lanelets share lane boundary
345 if(current_lanelet.leftBound() == ending_lanelet.rightBound()){
346 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Lanelet " << std::to_string(current_lanelet.id()) << " shares left boundary with " << std::to_string(ending_lanelet.id()));
347 is_lanechange_left = true;
348 shared_boundary_found = true;
349 }
350
351 else if(current_lanelet.rightBound() == ending_lanelet.leftBound()){
352 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Lanelet " << std::to_string(current_lanelet.id()) << " shares right boundary with " << std::to_string(ending_lanelet.id()));
353 shared_boundary_found = true;
354 }
355
356 else{
357 //If there are no following lanelets on route, lanechange should be completing before reaching it
358 if(wm->getMapRoutingGraph()->following(current_lanelet, false).empty())
359 {
360 // Maneuver requires we travel further before completing lane change, but no routable lanelet directly ahead
361 //In this case we have reached a lanelet which does not have a routable lanelet ahead + isn't adjacent to the lanelet where lane change ends
362 //A lane change should have already happened at this point
363 throw(std::invalid_argument("No following lanelets from current lanelet reachable without a lane change, incorrectly chosen end lanelet"));
364 }
365
366 current_lanelet = wm->getMapRoutingGraph()->following(current_lanelet, false).front();
367 if(current_lanelet.id() == starting_lanelet.id()){
368 //Looped back to starting lanelet
369 throw(std::invalid_argument("No lane change in path"));
370 }
371 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Now checking for shared lane boundary with lanelet " << std::to_string(current_lanelet.id()) << " and ending lanelet " << std::to_string(ending_lanelet.id()));
372 auto current_lanelet_linestring = current_lanelet.centerline2d().basicLineString();
373 //Concatenate linestring starting from + 1 to avoid overlap
374 reference_centerline.insert(reference_centerline.end(), current_lanelet_linestring.begin() + 1, current_lanelet_linestring.end());
375 starting_lane.push_back(current_lanelet);
376 }
377 }
378
379 // Create the target lane centerline using lanelets adjacent to the lanechange lanelets in the starting lane
380 std::vector<lanelet::BasicPoint2d> target_lane_centerline;
381 for(size_t i = 0;i<starting_lane.size();++i){
382 lanelet::ConstLanelet curr_end_lanelet;
383
384 if(is_lanechange_left){
385
386 //get left lanelet
387 if(wm->getMapRoutingGraph()->left(starting_lane[i])){
388 curr_end_lanelet = wm->getMapRoutingGraph()->left(starting_lane[i]).get();
389 }
390 else{
391 curr_end_lanelet = wm->getMapRoutingGraph()->adjacentLeft(starting_lane[i]).get();
392 }
393 }
394 else{
395
396 //get right lanelet
397 if(wm->getMapRoutingGraph()->right(starting_lane[i])){
398 curr_end_lanelet = wm->getMapRoutingGraph()->right(starting_lane[i]).get();
399 }
400 else{
401 curr_end_lanelet = wm->getMapRoutingGraph()->adjacentRight(starting_lane[i]).get();
402 }
403 }
404
405 auto target_lane_linestring = curr_end_lanelet.centerline2d().basicLineString();
406 //Concatenate linestring starting from + 1 to avoid overlap
407 target_lane_centerline.insert(target_lane_centerline.end(), target_lane_linestring.begin() + 1, target_lane_linestring.end());
408
409 }
410
411 //Downsample centerlines
412 // 400 value here is an arbitrary attempt at improving performance by reducing copy operations.
413 // Value picked based on annecdotal evidence from STOL system testing
414
415 std::vector<lanelet::BasicPoint2d> downsampled_starting_centerline;
416 downsampled_starting_centerline.reserve(400);
417 downsampled_starting_centerline = carma_ros2_utils::containers::downsample_vector(reference_centerline, downsample_ratio);
418
419 std::vector<lanelet::BasicPoint2d> downsampled_target_centerline;
420 downsampled_target_centerline.reserve(400);
421 downsampled_target_centerline = carma_ros2_utils::containers::downsample_vector(target_lane_centerline, downsample_ratio);
422
423 // Constrain centerlines to starting and ending downtrack
424 int start_index_starting_centerline = waypoint_generation::get_nearest_index_by_downtrack(downsampled_starting_centerline, wm, starting_downtrack);
425 carma_planning_msgs::msg::VehicleState start_state;
426 start_state.x_pos_global = downsampled_starting_centerline[start_index_starting_centerline].x();
427 start_state.y_pos_global = downsampled_starting_centerline[start_index_starting_centerline].y();
428 int start_index_target_centerline = waypoint_generation::get_nearest_point_index(downsampled_target_centerline, start_state);
429
430 int end_index_target_centerline = waypoint_generation::get_nearest_index_by_downtrack(downsampled_target_centerline, wm, ending_downtrack);
431 carma_planning_msgs::msg::VehicleState end_state;
432 end_state.x_pos_global = downsampled_target_centerline[end_index_target_centerline].x();
433 end_state.y_pos_global = downsampled_target_centerline[end_index_target_centerline].y();
434 int end_index_starting_centerline = waypoint_generation::get_nearest_point_index(downsampled_starting_centerline, end_state);
435
436 std::vector<lanelet::BasicPoint2d> constrained_start_centerline(downsampled_starting_centerline.begin() + start_index_starting_centerline, downsampled_starting_centerline.begin() + end_index_starting_centerline);
437 std::vector<lanelet::BasicPoint2d> constrained_target_centerline(downsampled_target_centerline.begin() + start_index_target_centerline, downsampled_target_centerline.begin() + end_index_target_centerline);
438
439 // If constrained centerlines are not the same size - resample to ensure same size along both centerlines
440 if(constrained_start_centerline.size() != constrained_target_centerline.size())
441 {
442 auto centerlines = resample_linestring_pair_to_same_size(constrained_start_centerline, constrained_target_centerline);
443 constrained_start_centerline = centerlines[0];
444 constrained_target_centerline = centerlines[1];
445
446 }
447
448 //Create Trajectory geometry
449 double delta_step = 1.0 / constrained_start_centerline.size();
450
451 for (size_t i = 0; i < constrained_start_centerline.size(); ++i)
452 {
453 lanelet::BasicPoint2d current_position;
454 lanelet::BasicPoint2d start_lane_pt = constrained_start_centerline[i];
455 lanelet::BasicPoint2d target_lane_pt = constrained_target_centerline[i];
456 double delta = delta_step * i;
457 current_position.x() = target_lane_pt.x() * delta + (1 - delta) * start_lane_pt.x();
458 current_position.y() = target_lane_pt.y() * delta + (1 - delta) * start_lane_pt.y();
459
460 centerline_points.push_back(current_position);
461 }
462
463 // Add points from the remaining length of the target lanelet to provide sufficient distance for adding buffer
464 double dist_to_target_lane_end = lanelet::geometry::distance2d(centerline_points.back(), downsampled_target_centerline.back());
465 centerline_points.insert(centerline_points.end(), downsampled_target_centerline.begin() + end_index_target_centerline, downsampled_target_centerline.end());
466
467 // If the additional distance from the remaining length of the target lanelet does not provide more than the required
468 // buffer_ending_downtrack, then also add points from the lanelet following the target lanelet
469 if (dist_to_target_lane_end < buffer_ending_downtrack) {
470 auto following_lanelets = wm->getMapRoutingGraph()->following(ending_lanelet, false);
471 if(!following_lanelets.empty()){
472 //Arbitrarily choosing first following lanelet for buffer since points are only being used to fit spline
473 auto following_lanelet_centerline = following_lanelets.front().centerline2d().basicLineString();
474 centerline_points.insert(centerline_points.end(), following_lanelet_centerline.begin(),
475 following_lanelet_centerline.end());
476 }
477 }
478
479 return centerline_points;
480 }
std::vector< std::vector< lanelet::BasicPoint2d > > resample_linestring_pair_to_same_size(std::vector< lanelet::BasicPoint2d > &line_1, std::vector< lanelet::BasicPoint2d > &line_2)
Resamples a pair of basicpoint2d lines to get lines of same number of points.
auto to_string(const UtmZone &zone) -> std::string
Definition: utm_zone.cpp:21

References BASIC_AUTONOMY_LOGGER, get_nearest_index_by_downtrack(), get_nearest_point_index(), process_bag::i, resample_linestring_pair_to_same_size(), and carma_cooperative_perception::to_string().

Referenced by get_lanechange_points_from_maneuver().

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

◆ create_lanechange_path()

lanelet::BasicLineString2d basic_autonomy::waypoint_generation::create_lanechange_path ( const lanelet::ConstLanelet &  start_lanelet,
const lanelet::ConstLanelet &  end_lanelet 
)

Given a start and end point, create a vector of points fit through a spline between the points (using a Spline library)

Parameters
start_laneletThe lanelet from which lane change starts
end_laneletThe lanelet in which lane change ends
Returns
A linestring path from start to end fit through Spline Library

◆ create_lanefollow_geometry()

std::vector< PointSpeedPair > basic_autonomy::waypoint_generation::create_lanefollow_geometry ( const carma_planning_msgs::msg::Maneuver &  maneuver,
double  max_starting_downtrack,
const carma_wm::WorldModelConstPtr wm,
const GeneralTrajConfig general_config,
const DetailedTrajConfig detailed_config,
std::unordered_set< lanelet::Id > &  visited_lanelets 
)

Converts a set of requested LANE_FOLLOWING maneuvers to point speed limit pairs.

Parameters
maneuversThe list of maneuvers to convert geometry points and calculate associated speed
max_starting_downtrackThe maximum downtrack that is allowed for the first maneuver. This should be set to the vehicle position or earlier. If the first maneuver exceeds this then it's downtrack will be shifted to this value.
wmPointer to intialized world model for semantic map access
general_configBasic autonomy struct defined to load general config parameters from tactical plugins
detailed_configBasic autonomy struct defined to load detailed config parameters from tactical plugins
Returns
List of centerline points paired with speed limits

Definition at line 68 of file basic_autonomy.cpp.

71 {
72 if(maneuver.type != carma_planning_msgs::msg::Maneuver::LANE_FOLLOWING){
73 throw std::invalid_argument("Create_lanefollow called on a maneuver type which is not LANE_FOLLOW");
74 }
75 std::vector<PointSpeedPair> points_and_target_speeds;
76
77 carma_planning_msgs::msg::LaneFollowingManeuver lane_following_maneuver = maneuver.lane_following_maneuver;
78
79 if (maneuver.lane_following_maneuver.lane_ids.empty())
80 {
81 throw std::invalid_argument("No lanelets are defined for lanefollow maneuver");
82 }
83
84 std::vector<lanelet::ConstLanelet> lanelets = { wm->getMap()->laneletLayer.get(stoi(lane_following_maneuver.lane_ids[0]))}; // Accept first lanelet reguardless
85 for (size_t i = 1; i < lane_following_maneuver.lane_ids.size(); i++) // Iterate over remaining lanelets and check if they are followers of the previous lanelet
86 {
87 auto ll_id = lane_following_maneuver.lane_ids[i];
88 int cur_id = stoi(ll_id);
89 auto cur_ll = wm->getMap()->laneletLayer.get(cur_id);
90 auto following_lanelets = wm->getMapRoutingGraph()->following(lanelets.back());
91
92 bool is_follower = false;
93 for (auto follower_ll : following_lanelets )
94 {
95 if (follower_ll.id() == cur_ll.id())
96 {
97 is_follower = true;
98 break;
99 }
100 }
101
102 if (!is_follower)
103 {
104 throw std::invalid_argument("Invalid list of lanelets they are not followers");
105 }
106
107 lanelets.push_back(cur_ll); // Keep lanelet
108
109 }
110
111 // Add extra lanelet to ensure there are sufficient points for buffer
112 auto extra_following_lanelets = wm->getMapRoutingGraph()->following(lanelets.back());
113
114 for (auto llt : wm->getRoute()->shortestPath())
115 {
116 for (size_t i = 0; i < extra_following_lanelets.size(); i++)
117 {
118 if (llt.id() == extra_following_lanelets[i].id())
119 {
120 lanelets.push_back(extra_following_lanelets[i]);
121 break;
122 }
123 }
124 }
125
126 if (lanelets.empty())
127 {
128 RCLCPP_ERROR_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Detected no lanelets between starting downtrack: "<< starting_downtrack << ", and lane_following_maneuver.end_dist: "<< lane_following_maneuver.end_dist);
129 throw std::invalid_argument("Detected no lanelets between starting_downtrack and end_dist");
130 }
131
132 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Maneuver");
133
134 lanelet::BasicLineString2d downsampled_centerline;
135 // 400 value here is an arbitrary attempt at improving inlane-cruising performance by reducing copy operations.
136 // Value picked based on annecdotal evidence from STOL system testing
137 downsampled_centerline.reserve(400);
138
139 //getLaneletsBetween is inclusive of lanelets between its two boundaries
140 //which may return lanechange lanelets, so
141 //exclude lanechanges and plan for only the straight part
142 size_t curr_idx = 0;
143 auto following_lanelets = wm->getMapRoutingGraph()->following(lanelets[curr_idx]);
144 lanelet::ConstLanelets straight_lanelets;
145
146 if(lanelets.size() <= 1) //no lane change anyways if only size 1
147 {
148 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Detected one straight lanelet Id:" << lanelets[curr_idx].id());
149 straight_lanelets = lanelets;
150 }
151 else
152 {
153 // skip all lanechanges until lane follow starts
154 while (curr_idx + 1 < lanelets.size() &&
155 std::find(following_lanelets.begin(),following_lanelets.end(), lanelets[curr_idx + 1]) == following_lanelets.end())
156 {
157 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "As there were no directly following lanelets after this, skipping lanelet id: " << lanelets[curr_idx].id());
158 curr_idx ++;
159 following_lanelets = wm->getMapRoutingGraph()->following(lanelets[curr_idx]);
160 }
161
162 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Added lanelet Id for lane follow: " << lanelets[curr_idx].id());
163 // guaranteed to have at least one "straight" lanelet (e.g the last one in the list)
164 straight_lanelets.push_back(lanelets[curr_idx]);
165 // add all lanelets on the straight road until next lanechange
166 while (curr_idx + 1 < lanelets.size() &&
167 std::find(following_lanelets.begin(),following_lanelets.end(), lanelets[curr_idx + 1]) != following_lanelets.end())
168 {
169 curr_idx++;
170 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Added lanelet Id forlane follow: " << lanelets[curr_idx].id());
171 straight_lanelets.push_back(lanelets[curr_idx]);
172 following_lanelets = wm->getMapRoutingGraph()->following(lanelets[curr_idx]);
173 }
174
175 }
176
177 for (auto l : straight_lanelets)
178 {
179 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Processing lanelet ID: " << l.id());
180 if (visited_lanelets.find(l.id()) == visited_lanelets.end())
181 {
182
183 bool is_turn = false;
184 if(l.hasAttribute("turn_direction")) {
185 std::string turn_direction = l.attribute("turn_direction").value();
186 is_turn = turn_direction.compare("left") == 0 || turn_direction.compare("right") == 0;
187 }
188
189 lanelet::BasicLineString2d centerline = l.centerline2d().basicLineString();
190 lanelet::BasicLineString2d downsampled_points;
191 if (is_turn) {
192 downsampled_points = carma_ros2_utils::containers::downsample_vector(centerline, general_config.turn_downsample_ratio);
193 } else {
194 downsampled_points = carma_ros2_utils::containers::downsample_vector(centerline, general_config.default_downsample_ratio);
195 }
196
197 if(downsampled_centerline.size() != 0 && downsampled_points.size() != 0 // If this is not the first lanelet and the points are closer than 1m drop the first point to prevent overlap
198 && lanelet::geometry::distance2d(downsampled_points.front(), downsampled_centerline.back()) <1.2){
199 downsampled_points = lanelet::BasicLineString2d(downsampled_points.begin() + 1, downsampled_points.end());
200 }
201
202 downsampled_centerline = carma_wm::geometry::concatenate_line_strings(downsampled_centerline, downsampled_points);
203 visited_lanelets.insert(l.id());
204 }
205 }
206
207 bool first = true;
208 for (auto p : downsampled_centerline)
209 {
210 if (first && !points_and_target_speeds.empty())
211 {
212 first = false;
213 continue; // Skip the first point if we have already added points from a previous maneuver to avoid duplicates
214 }
215 PointSpeedPair pair;
216 pair.point = p;
217 pair.speed = lane_following_maneuver.end_speed;
218 points_and_target_speeds.push_back(pair);
219 }
220
221 return points_and_target_speeds;
222
223 }
lanelet::BasicLineString2d concatenate_line_strings(const lanelet::BasicLineString2d &l1, const lanelet::BasicLineString2d &l2)
Helper function to concatenate 2 linestrings together and return the result. Neither LineString is mo...
Definition: Geometry.cpp:373

References BASIC_AUTONOMY_LOGGER, carma_wm::geometry::concatenate_line_strings(), basic_autonomy::waypoint_generation::GeneralTrajConfig::default_downsample_ratio, process_bag::i, basic_autonomy::waypoint_generation::PointSpeedPair::point, basic_autonomy::waypoint_generation::PointSpeedPair::speed, and basic_autonomy::waypoint_generation::GeneralTrajConfig::turn_downsample_ratio.

Referenced by create_geometry_profile(), and light_controlled_intersection_tactical_plugin::LightControlledIntersectionTacticalPlugin::createGeometryProfile().

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

◆ create_route_geom()

std::vector< lanelet::BasicPoint2d > basic_autonomy::waypoint_generation::create_route_geom ( double  starting_downtrack,
int  starting_lane_id,
double  ending_downtrack,
const carma_wm::WorldModelConstPtr wm 
)

Creates a Lanelet2 Linestring from a vector or points along the geometry.

Parameters
starting_downtrackdowntrack along route where maneuver starts
ending_downtrackdowntrack along route where maneuver starts
wmPointer to intialized world model for semantic map access
Returns
Points in a path from starting downtrack to ending downtrack

◆ get_lanechange_points_from_maneuver()

std::vector< PointSpeedPair > basic_autonomy::waypoint_generation::get_lanechange_points_from_maneuver ( const carma_planning_msgs::msg::Maneuver &  maneuver,
double  max_starting_downtrack,
const carma_wm::WorldModelConstPtr wm,
carma_planning_msgs::msg::VehicleState &  ending_state_before_buffer,
const carma_planning_msgs::msg::VehicleState &  state,
const GeneralTrajConfig general_config,
const DetailedTrajConfig detailed_config 
)

Converts a set of requested LANE_CHANGE maneuvers to point speed limit pairs.

Parameters
maneuversThe list of maneuvers to convert
max_starting_downtrackThe maximum downtrack that is allowed for the first maneuver. This should be set to the vehicle position or earlier. If the first maneuver exceeds this then it's downtrack will be shifted to this value.
wmPointer to intialized world model for semantic map access
ending_state_before_bufferreference to Vehicle state, which is state before applying extra points for curvature calculation that are removed later
stateThe vehicle state at the time the function is called
general_configBasic autonomy struct defined to load general config parameters from tactical plugins
detailed_configBasic autonomy struct defined to load detailed config parameters from tactical plugins
Returns
A vector of point speed pair struct which contains geometry points as basicpoint::lanelet2d and speed as a double for the maneuver

Definition at line 544 of file basic_autonomy.cpp.

547 {
548 if(maneuver.type != carma_planning_msgs::msg::Maneuver::LANE_CHANGE){
549 throw std::invalid_argument("Create_lanechange called on a maneuver type which is not LANE_CHANGE");
550 }
551 std::vector<PointSpeedPair> points_and_target_speeds;
552 std::unordered_set<lanelet::Id> visited_lanelets;
553
554 carma_planning_msgs::msg::LaneChangeManeuver lane_change_maneuver = maneuver.lane_change_maneuver;
555 double ending_downtrack = lane_change_maneuver.end_dist;
556 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Maneuver ending downtrack:"<<ending_downtrack);
557 if(starting_downtrack >= ending_downtrack)
558 {
559 throw(std::invalid_argument("Start distance is greater than or equal to ending distance"));
560 }
561
562 //get route between starting and ending downtracks - downtracks should be constant for complete length of maneuver
563 std::vector<lanelet::BasicPoint2d> route_geometry = create_lanechange_geometry(std::stoi(lane_change_maneuver.starting_lane_id),std::stoi(lane_change_maneuver.ending_lane_id),
564 starting_downtrack, ending_downtrack, wm, general_config.default_downsample_ratio, detailed_config.buffer_ending_downtrack);
565 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Route geometry size:"<<route_geometry.size());
566
567 lanelet::BasicPoint2d state_pos(state.x_pos_global, state.y_pos_global);
568 double current_downtrack = wm->routeTrackPos(state_pos).downtrack;
569 int nearest_pt_index = get_nearest_index_by_downtrack(route_geometry, wm, current_downtrack);
570 int ending_pt_index = get_nearest_index_by_downtrack(route_geometry, wm, ending_downtrack);
571 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Nearest pt index in maneuvers to points: "<< nearest_pt_index);
572 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Ending pt index in maneuvers to points: "<< ending_pt_index);
573
574 ending_state_before_buffer.x_pos_global = route_geometry[ending_pt_index].x();
575 ending_state_before_buffer.y_pos_global = route_geometry[ending_pt_index].y();
576
577 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "ending_state_before_buffer_:"<<ending_state_before_buffer.x_pos_global <<
578 ", ending_state_before_buffer_.y_pos_global" << ending_state_before_buffer.y_pos_global);
579
580
581 double route_length = wm->getRouteEndTrackPos().downtrack;
582
583 if (ending_downtrack + detailed_config.buffer_ending_downtrack < route_length)
584 {
585 ending_pt_index = get_nearest_index_by_downtrack(route_geometry, wm, ending_downtrack + detailed_config.buffer_ending_downtrack);
586 }
587 else
588 {
589 ending_pt_index = route_geometry.size() - 1;
590 }
591
592 lanelet::BasicLineString2d future_route_geometry(route_geometry.begin() + nearest_pt_index, route_geometry.begin() + ending_pt_index);
593 bool first = true;
594 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Future geom size:"<< future_route_geometry.size());
595
596 for (auto p : future_route_geometry)
597 {
598 if (first && !points_and_target_speeds.empty())
599 {
600 first = false;
601 continue; // Skip the first point if we have already added points from a previous maneuver to avoid duplicates
602 }
603 PointSpeedPair pair;
604 pair.point = p;
605 //If current speed is above min speed, keep at current speed. Otherwise use end speed from maneuver.
606 pair.speed = (state.longitudinal_vel > detailed_config.minimum_speed) ? state.longitudinal_vel : lane_change_maneuver.end_speed;
607 points_and_target_speeds.push_back(pair);
608
609 }
610 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Const speed assigned:"<<points_and_target_speeds.back().speed);
611 return points_and_target_speeds;
612
613
614 }
std::vector< lanelet::BasicPoint2d > create_lanechange_geometry(lanelet::Id starting_lane_id, lanelet::Id ending_lane_id, double starting_downtrack, double ending_downtrack, const carma_wm::WorldModelConstPtr &wm, int downsample_ratio, double buffer_ending_downtrack)
Creates a vector of lane change points using parameters defined.

References BASIC_AUTONOMY_LOGGER, basic_autonomy::waypoint_generation::DetailedTrajConfig::buffer_ending_downtrack, create_lanechange_geometry(), basic_autonomy::waypoint_generation::GeneralTrajConfig::default_downsample_ratio, get_nearest_index_by_downtrack(), basic_autonomy::waypoint_generation::DetailedTrajConfig::minimum_speed, basic_autonomy::waypoint_generation::PointSpeedPair::point, and basic_autonomy::waypoint_generation::PointSpeedPair::speed.

Referenced by create_geometry_profile().

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

◆ get_nearest_index_by_downtrack() [1/3]

int basic_autonomy::waypoint_generation::get_nearest_index_by_downtrack ( const std::vector< lanelet::BasicPoint2d > &  points,
const carma_wm::WorldModelConstPtr wm,
const carma_planning_msgs::msg::VehicleState &  state 
)

Overload: Returns the nearest point to the provided vehicle pose in the provided list by utilizing the downtrack measured along the route NOTE: This function compares the downtrack, provided by routeTrackPos, of each points in the list to get the closest one to the given point's downtrack. Therefore, it is rather costlier method than comparing cartesian distance between the points and getting the closest. This way, however, the function correctly returns the end point if the given state, despite being valid, is farther than the given points and can technically be near any of them.

Parameters
pointsThe points to evaluate
stateThe current vehicle state
wmThe carma world model
Returns
index of nearest point in points

Definition at line 117 of file helper_functions.cpp.

119 {
120 lanelet::BasicPoint2d state_pos(state.x_pos_global, state.y_pos_global);
121 double ending_downtrack = wm->routeTrackPos(state_pos).downtrack;
122 return get_nearest_index_by_downtrack(points, wm, ending_downtrack);
123 }

References get_nearest_index_by_downtrack().

Here is the call graph for this function:

◆ get_nearest_index_by_downtrack() [2/3]

int basic_autonomy::waypoint_generation::get_nearest_index_by_downtrack ( const std::vector< lanelet::BasicPoint2d > &  points,
const carma_wm::WorldModelConstPtr wm,
double  target_downtrack 
)

Returns the nearest "less than" point to the provided vehicle pose in the provided list by utilizing the downtrack measured along the route NOTE: This function compares the downtrack, provided by routeTrackPos, of each points in the list to get the closest one to the given point's downtrack. Therefore, it is rather costlier method than comparing cartesian distance between the points and getting the closest. This way, however, the function correctly returns the end point's index if the given state, despite being valid, is farther than the given points and can technically be near any of them.

Parameters
pointsBasicLineString2d points
target_downtracktarget downtrack along the route to get index near to
Returns
index of nearest point in points with a downtrack less than 'target_downtrack', or -1 if the received 'points' vector is empty.

Definition at line 66 of file helper_functions.cpp.

67 {
68 if(std::empty(points)){
69 RCLCPP_WARN_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Empty points vector received, returning -1");
70 return -1;
71 }
72
73 // Find first point with a downtrack greater than target_downtrack
74 const auto itr = std::find_if(std::cbegin(points), std::cend(points),
75 [&wm = std::as_const(wm), target_downtrack](const auto & point) { return wm->routeTrackPos(point).downtrack > target_downtrack; });
76
77 int best_index = std::size(points) - 1;
78
79 // Set best_index to the last point with a downtrack less than target_downtrack
80 if(itr != std::cbegin(points)){
81 best_index = std::distance(std::cbegin(points), std::prev(itr));
82 }
83 else{
84 best_index = 0;
85 }
86
87 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "get_nearest_index_by_downtrack>> Found best_index: " << best_index<<", points[i].x(): " << points.at(best_index).x() << ", points[i].y(): " << points.at(best_index).y());
88
89 return best_index;
90 }

References BASIC_AUTONOMY_LOGGER, and process_traj_logs::point.

Referenced by compose_lanechange_trajectory_from_path(), compose_lanefollow_trajectory_from_path(), stop_controlled_intersection_tactical_plugin::StopControlledIntersectionTacticalPlugin::compose_trajectory_from_centerline(), create_lanechange_geometry(), get_lanechange_points_from_maneuver(), and get_nearest_index_by_downtrack().

Here is the caller graph for this function:

◆ get_nearest_index_by_downtrack() [3/3]

int basic_autonomy::waypoint_generation::get_nearest_index_by_downtrack ( const std::vector< PointSpeedPair > &  points,
const carma_wm::WorldModelConstPtr wm,
const carma_planning_msgs::msg::VehicleState &  state 
)

Overload: Returns the nearest point to the provided vehicle pose in the provided list by utilizing the downtrack measured along the route NOTE: This function compares the downtrack, provided by routeTrackPos, of each points in the list to get the closest one to the given point's downtrack. Therefore, it is rather costlier method than comparing cartesian distance between the points and getting the closest. This way, however, the function correctly returns the end point's index if the given state, despite being valid, is farther than the given points and can technically be near any of them.

Parameters
pointsThe points and speed pairs to evaluate
stateThe current vehicle state
wmThe carma world model
Returns
index of nearest point in points

Definition at line 106 of file helper_functions.cpp.

108 {
109 lanelet::BasicPoint2d state_pos(state.x_pos_global, state.y_pos_global);
110 double ending_downtrack = wm->routeTrackPos(state_pos).downtrack;
111 std::vector<lanelet::BasicPoint2d> basic_points;
112 std::vector<double> speeds;
113 split_point_speed_pairs(points, &basic_points, &speeds);
114 return get_nearest_index_by_downtrack(basic_points, wm, ending_downtrack);
115 }

References get_nearest_index_by_downtrack(), and split_point_speed_pairs().

Here is the call graph for this function:

◆ get_nearest_point_index() [1/2]

int basic_autonomy::waypoint_generation::get_nearest_point_index ( const std::vector< lanelet::BasicPoint2d > &  points,
const carma_planning_msgs::msg::VehicleState &  state 
)

Returns the nearest point (in terms of cartesian 2d distance) to the provided vehicle pose in the provided l.

Parameters
pointsThe points to evaluate
stateThe current vehicle state
Returns
index of nearest point in points

Definition at line 25 of file helper_functions.cpp.

27 {
28 lanelet::BasicPoint2d veh_point(state.x_pos_global, state.y_pos_global);
29 double min_distance = std::numeric_limits<double>::max();
30 int i = 0;
31 int best_index = 0;
32 for (const auto& p : points)
33 {
34 double distance = lanelet::geometry::distance2d(p, veh_point);
35 if (distance < min_distance)
36 {
37 best_index = i;
38 min_distance = distance;
39 }
40 i++;
41 }
42 return best_index;
43 }

References process_bag::i.

Referenced by compose_lanefollow_trajectory_from_path(), stop_controlled_intersection_tactical_plugin::StopControlledIntersectionTacticalPlugin::compose_trajectory_from_centerline(), and create_lanechange_geometry().

Here is the caller graph for this function:

◆ get_nearest_point_index() [2/2]

int basic_autonomy::waypoint_generation::get_nearest_point_index ( const std::vector< PointSpeedPair > &  points,
const carma_planning_msgs::msg::VehicleState &  state 
)

Returns the nearest point (in terms of cartesian 2d distance) to the provided vehicle pose in the provided list.

Parameters
pointsThe points to evaluate
stateThe current vehicle state
Returns
index of nearest point in points

Definition at line 45 of file helper_functions.cpp.

47 {
48 lanelet::BasicPoint2d veh_point(state.x_pos_global, state.y_pos_global);
49 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "veh_point: " << veh_point.x() << ", " << veh_point.y());
50 double min_distance = std::numeric_limits<double>::max();
51 int i = 0;
52 int best_index = 0;
53 for (const auto& p : points)
54 {
55 double distance = lanelet::geometry::distance2d(p.point, veh_point);
56 if (distance < min_distance)
57 {
58 best_index = i;
59 min_distance = distance;
60 }
61 i++;
62 }
63 return best_index;
64 }

References BASIC_AUTONOMY_LOGGER, and process_bag::i.

◆ is_valid_yield_plan()

bool basic_autonomy::waypoint_generation::is_valid_yield_plan ( const std::shared_ptr< carma_ros2_utils::CarmaLifecycleNode > &  node_handler,
const carma_planning_msgs::msg::TrajectoryPlan &  yield_plan 
)

Helper function to verify if the input yield trajectory plan is valid.

Parameters
node_handlernode of which time to compare against the trajectory's time
yield_planinput yield trajectory plan
Returns
true or false

Definition at line 1316 of file basic_autonomy.cpp.

1317 {
1318 if (yield_plan.trajectory_points.size() < 2)
1319 {
1320 RCLCPP_WARN(node_handler->get_logger(), "Invalid Yield Trajectory");
1321 }
1322
1323 RCLCPP_DEBUG_STREAM(node_handler->get_logger(), "Yield Trajectory Time" << rclcpp::Time(yield_plan.trajectory_points[0].target_time).seconds());
1324 RCLCPP_DEBUG_STREAM(node_handler->get_logger(), "Now:" << node_handler->now().seconds());
1325
1326 if (rclcpp::Time(yield_plan.trajectory_points[0].target_time) + rclcpp::Duration(5.0, 0) > node_handler->now())
1327 {
1328 return true;
1329 }
1330 else
1331 {
1332 RCLCPP_DEBUG(node_handler->get_logger(), "Old Yield Trajectory");
1333 }
1334
1335 return false;
1336 }

Referenced by modify_trajectory_to_yield_to_obstacles().

Here is the caller graph for this function:

◆ min_with_exclusions()

std::pair< double, size_t > basic_autonomy::waypoint_generation::min_with_exclusions ( const std::vector< double > &  values,
const std::unordered_set< size_t > &  excluded 
)

Returns the min, and its idx, from the vector of values, excluding given set of values.

Parameters
valuesvector of values
excludedset of excluded values
Returns
minimum value and its idx

Definition at line 679 of file basic_autonomy.cpp.

680 {
681 double min = std::numeric_limits<double>::max();
682 size_t best_idx = -1;
683 for (size_t i = 0; i < values.size(); i++)
684 {
685 if (excluded.find(i) != excluded.end())
686 {
687 continue;
688 }
689
690 if (values[i] < min)
691 {
692 min = values[i];
693 best_idx = i;
694 }
695 }
696 return std::make_pair(min, best_idx);
697 }

References process_bag::i.

Referenced by optimize_speed().

Here is the caller graph for this function:

◆ modify_trajectory_to_yield_to_obstacles()

carma_planning_msgs::srv::PlanTrajectory::Response::SharedPtr basic_autonomy::waypoint_generation::modify_trajectory_to_yield_to_obstacles ( const std::shared_ptr< carma_ros2_utils::CarmaLifecycleNode > &  node_handler,
const carma_planning_msgs::srv::PlanTrajectory::Request::SharedPtr &  req,
const carma_planning_msgs::srv::PlanTrajectory::Response::SharedPtr &  resp,
const carma_ros2_utils::ClientPtr< carma_planning_msgs::srv::PlanTrajectory > &  yield_client,
int  yield_plugin_service_call_timeout 
)

Applies a yield trajectory to the original trajectory set in response.

Parameters
node_handlera node interface to use the logger and time
reqThe service request containing the maneuvers to plan trajectories for and current vehicle state
respThe original response containing the planned trajectory to be modified
yield_clientyield_client to call for
yield_plugin_service_call_timeoutyield client's timeout in milliseconds int
Returns
The original response modified to contain the modified planned trajectory

Definition at line 1338 of file basic_autonomy.cpp.

1344 {
1345 RCLCPP_DEBUG(node_handler->get_logger(), "Activate Object Avoidance");
1346
1347 if (!yield_client || !yield_client->service_is_ready())
1348 {
1349 throw std::runtime_error("Yield Client is not set or unavailable after configuration state of lifecycle");
1350 }
1351
1352 RCLCPP_DEBUG(node_handler->get_logger(), "Yield Client is valid");
1353
1354 auto yield_srv = std::make_shared<carma_planning_msgs::srv::PlanTrajectory::Request>();
1355 yield_srv->initial_trajectory_plan = resp->trajectory_plan;
1356 yield_srv->vehicle_state = req->vehicle_state;
1357
1358 auto yield_resp = yield_client->async_send_request(yield_srv);
1359
1360 auto future_status = yield_resp.wait_for(std::chrono::milliseconds(yield_plugin_service_call_timeout));
1361
1362 if (future_status != std::future_status::ready)
1363 {
1364 // Sometimes the yield plugin's service call may be unsuccessful due to its computationally expensive logic.
1365 // However, consecutive calls can be successful, so return original trajectory for now
1366 RCLCPP_WARN(node_handler->get_logger(), "Service request to yield plugin timed out waiting on a reply from the service server");
1367 return resp;
1368 }
1369
1370 RCLCPP_DEBUG(node_handler->get_logger(), "Received Traj from Yield");
1371 carma_planning_msgs::msg::TrajectoryPlan yield_plan = yield_resp.get()->trajectory_plan;
1372 if (is_valid_yield_plan(node_handler, yield_plan))
1373 {
1374 RCLCPP_DEBUG(node_handler->get_logger(), "Yield trajectory validated");
1375 resp->trajectory_plan = yield_plan;
1376 }
1377 else
1378 {
1379 throw std::invalid_argument("Invalid Yield Trajectory");
1380 }
1381
1382 return resp;
1383 }
bool is_valid_yield_plan(const std::shared_ptr< carma_ros2_utils::CarmaLifecycleNode > &node_handler, const carma_planning_msgs::msg::TrajectoryPlan &yield_plan)
Helper function to verify if the input yield trajectory plan is valid.

References is_valid_yield_plan().

Referenced by inlanecruising_plugin::InLaneCruisingPlugin::plan_trajectory_callback(), stop_and_wait_plugin::StopandWait::plan_trajectory_cb(), and light_controlled_intersection_tactical_plugin::LightControlledIntersectionTacticalPlugin::planTrajectoryCB().

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

◆ optimize_speed()

std::vector< double > basic_autonomy::waypoint_generation::optimize_speed ( const std::vector< double > &  downtracks,
const std::vector< double > &  curv_speeds,
double  accel_limit 
)

Applies the longitudinal acceleration limit to each point's speed.

Parameters
downtracksdowntrack distances corresponding to each speed
curv_speedsvehicle velocity in m/s.
accel_limitvehicle longitudinal acceleration in m/s^2.
Returns
optimized speeds for each dowtrack points that satisfies longitudinal acceleration

Definition at line 699 of file basic_autonomy.cpp.

700 {
701 if (downtracks.size() != curv_speeds.size())
702 {
703 throw std::invalid_argument("Downtracks and speeds do not have the same size");
704 }
705
706 if (accel_limit <= 0)
707 {
708 throw std::invalid_argument("Accel limits should be positive");
709 }
710
711 bool optimize = true;
712 std::unordered_set<size_t> visited_idx;
713 visited_idx.reserve(curv_speeds.size());
714
715 std::vector<double> output = curv_speeds;
716
717 while (optimize)
718 {
719 auto min_pair = min_with_exclusions(curv_speeds, visited_idx);
720 int min_idx = std::get<1>(min_pair);
721 if (min_idx == -1)
722 {
723 break;
724 }
725
726 visited_idx.insert(min_idx); // Mark this point as visited
727
728 double v_i = std::get<0>(min_pair);
729 double x_i = downtracks[min_idx];
730 for (int i = min_idx - 1; i > 0; i--)
731 { // NOTE: Do not use size_t for i type here as -- with > 0 will result in overflow
732 // First point's speed is left unchanged as it is current speed of the vehicle
733 double v_f = curv_speeds[i];
734 double dv = v_f - v_i;
735
736 double x_f = downtracks[i];
737 double dx = x_f - x_i;
738
739 if (dv > 0)
740 {
741 v_f = std::min(v_f, sqrt(v_i * v_i - 2 * accel_limit * dx)); // inverting accel as we are only visiting deceleration case
742 visited_idx.insert(i);
743 }
744 else if (dv < 0)
745 {
746 break;
747 }
748 output[i] = v_f;
749 v_i = v_f;
750 x_i = x_f;
751 }
752 }
753
754 log::printDoublesPerLineWithPrefix("only_reverse[i]: ", output);
755
756 output = trajectory_utils::apply_accel_limits_by_distance(downtracks, output, accel_limit, accel_limit);
757 log::printDoublesPerLineWithPrefix("after_forward[i]: ", output);
758
759 return output;
760 }
std::pair< double, size_t > min_with_exclusions(const std::vector< double > &values, const std::unordered_set< size_t > &excluded)
Returns the min, and its idx, from the vector of values, excluding given set of values.

References process_bag::i, min_with_exclusions(), and basic_autonomy::log::printDoublesPerLineWithPrefix().

Referenced by compose_lanefollow_trajectory_from_path().

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

◆ process_trajectory_plan()

autoware_auto_msgs::msg::Trajectory basic_autonomy::waypoint_generation::process_trajectory_plan ( const carma_planning_msgs::msg::TrajectoryPlan &  tp,
double  vehicle_response_lag 
)

Given a carma type of trajectory_plan, generate autoware type of trajectory accounting for speed_lag and stopping case Generated trajectory is meant to be used in autoware.auto's pure_pursuit library using set_trajectory() function.

Parameters
tptrajectory plan from tactical plugins
Returns
trajectory plan of autoware_auto_msgs type

Definition at line 1196 of file basic_autonomy.cpp.

1197 {
1198 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Processing latest TrajectoryPlan message");
1199
1200 std::vector<double> times;
1201 std::vector<double> downtracks;
1202
1203 std::vector<carma_planning_msgs::msg::TrajectoryPlanPoint> trajectory_points = tp.trajectory_points;
1204
1205 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Original Trajectory size:"<<trajectory_points.size());
1206
1207
1208 trajectory_utils::conversions::trajectory_to_downtrack_time(trajectory_points, &downtracks, &times);
1209
1210 //detect stopping case
1211 size_t stopping_index = 0;
1212 for (size_t i = 1; i < times.size(); i++)
1213 {
1214 if (times[i] == times[i - 1]) //if exactly same, it is stopping case
1215 {
1216 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Detected a stopping case where times is exactly equal: " << times[i-1]);
1217 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "And index of that is: " << i << ", where size is: " << times.size());
1218 stopping_index = i;
1219 break;
1220 }
1221 }
1222
1223 std::vector<double> speeds;
1224 try
1225 {
1226 trajectory_utils::conversions::time_to_speed(downtracks, times, tp.initial_longitudinal_velocity, &speeds);
1227 }
1228 catch(const std::runtime_error& error)
1229 {
1230 // This can only happen if there was negative speed in trajectory generation which usually happens when intending to stop.
1231 // The plugin is catching that error and logging it for the user to correct the origin plugin's logic, but continues
1232 // the operation by forcing the negative values to be 0, which is the intention usually.
1233 RCLCPP_WARN_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Detected a negative speed from <point,time> to <point,speed> trajectory conversion with error: "
1234 << error.what() << ". Replacing the negative speed with 0.0 speed, but please revisit the trajectory logic. "
1235 "Responsible plugin is: " << trajectory_points[std::find(speeds.begin(), speeds.end(), 0.0) - speeds.begin()].planner_plugin_name);
1236 }
1237
1238 if (speeds.size() != trajectory_points.size())
1239 {
1240 throw std::invalid_argument("Speeds and trajectory points sizes do not match");
1241 }
1242
1243 for (size_t i = 0; i < speeds.size(); i++) { // Ensure 0 is min speed
1244 if (stopping_index != 0 && i >= stopping_index - 1)
1245 {
1246 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Made it to 0, i: " << i);
1247
1248 speeds[i] = 0.0; //stopping case
1249 }
1250 else
1251 {
1252 speeds[i] = std::max(0.0, speeds[i]);
1253 }
1254 }
1255
1256 std::vector<double> lag_speeds;
1257 lag_speeds = apply_response_lag(speeds, downtracks, vehicle_response_lag); // This call requires that the first speed point be current speed to work as expected
1258
1259 autoware_auto_msgs::msg::Trajectory autoware_trajectory;
1260 autoware_trajectory.header = tp.header;
1261 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "size: " << trajectory_points.size());
1262
1263 auto max_size = std::min(99, (int)trajectory_points.size()); //NOTE: more than this size autoware auto raises exception with "Exceeded upper bound while in ACTIVE state."
1264 //large portion of the points are not needed anyways
1265 for (int i = 0; i < max_size; i++)
1266 {
1267 autoware_auto_msgs::msg::TrajectoryPoint autoware_point;
1268
1269 autoware_point.x = trajectory_points[i].x;
1270 autoware_point.y = trajectory_points[i].y;
1271 autoware_point.longitudinal_velocity_mps = lag_speeds[i];
1272 double yaw = 0.0;
1273 if (i< max_size-1)
1274 {
1275 yaw = std::atan2(trajectory_points[i+1].y - trajectory_points[i].y, trajectory_points[i+1].x - trajectory_points[i].x);
1276
1277 }
1278 else
1279 {
1280 yaw = std::atan2(trajectory_points[max_size-1].y - trajectory_points[max_size-2].y, trajectory_points[max_size-1].x - trajectory_points[max_size-2].x);
1281 // last point in the trajectory will have yaw value of its previous point to avoid sudden steering in some conditions
1282 }
1283 autoware_point.heading.real = std::cos(yaw/2);
1284 autoware_point.heading.imag = std::sin(yaw/2);
1285
1286 autoware_point.time_from_start = rclcpp::Duration(times[i] * 1e9);
1287 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Setting waypoint idx: " << i <<", with planner: << " << trajectory_points[i].planner_plugin_name << ", x: " << trajectory_points[i].x <<
1288 ", y: " << trajectory_points[i].y <<
1289 ", speed: " << lag_speeds[i]* 2.23694 << "mph");
1290 autoware_trajectory.points.push_back(autoware_point);
1291 }
1292
1293 return autoware_trajectory;
1294 }
std::vector< double > apply_response_lag(const std::vector< double > &speeds, const std::vector< double > downtracks, double response_lag)
Applies a specified response lag in seconds to the trajectory shifting the whole thing by the specifi...

References apply_response_lag(), BASIC_AUTONOMY_LOGGER, process_bag::i, process_traj_logs::x, and process_traj_logs::y.

Referenced by trajectory_follower_wrapper::TrajectoryFollowerWrapperNode::autoware_info_timer_callback(), pure_pursuit_wrapper::PurePursuitWrapperNode::generate_command(), and platooning_control::PlatooningControlPlugin::generate_control_signals().

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

◆ resample_linestring_pair_to_same_size()

std::vector< std::vector< lanelet::BasicPoint2d > > basic_autonomy::waypoint_generation::resample_linestring_pair_to_same_size ( std::vector< lanelet::BasicPoint2d > &  line_1,
std::vector< lanelet::BasicPoint2d > &  line_2 
)

Resamples a pair of basicpoint2d lines to get lines of same number of points.

Parameters
line_1a vector of points to be resampled
line_2a vector of points to be resampled
Returns
A 2d vector with input lines resampled at same rate. The first iteration is the resampled line_1 and the resampled line_2 is the second iteration Assumption here is for lane change to happen between two adjacent lanelets, they must share a lane boundary (linestring)

Definition at line 482 of file basic_autonomy.cpp.

482 {
483
484 auto start_time = std::chrono::high_resolution_clock::now(); // Start timing the execution time for planning so it can be logged
485
486 std::vector<std::vector<lanelet::BasicPoint2d>> output;
487
488 //Fit centerlines to a spline
489 std::unique_ptr<smoothing::SplineI> fit_curve_1 = compute_fit(line_1); // Compute splines based on curve points
490 if (!fit_curve_1)
491 {
492 throw std::invalid_argument("Could not fit a spline curve along the starting_lane centerline points!");
493 }
494
495 std::unique_ptr<smoothing::SplineI> fit_curve_2 = compute_fit(line_2); // Compute splines based on curve points
496 if (!fit_curve_2)
497 {
498 throw std::invalid_argument("Could not fit a spline curve along the ending_lane centerline points!");
499 }
500
501 //Sample spline to get centerlines of equal size
502 std::vector<lanelet::BasicPoint2d> all_sampling_points_line1;
503 std::vector<lanelet::BasicPoint2d> all_sampling_points_line2;
504
505 size_t total_point_size = std::min(line_1.size(), line_2.size());
506
507 all_sampling_points_line1.reserve(1 + total_point_size * 2);
508 std::vector<double> downtracks_raw_line1 = carma_wm::geometry::compute_arc_lengths(line_1);
509 //int total_step_along_curve1 = static_cast<int>(downtracks_raw_line1.back() / 2.0);
510 //double step_threshold_line1 = (double)total_step_along_curve1 / (double)total_point_size;
511 //TODO: are we missing some computation here? step_threshold_line1 and step_threshold_line2 are not used anywhere
512 // and these calcs can be deleted (see below also).
513
514 all_sampling_points_line2.reserve(1 + total_point_size * 2);
515 std::vector<double> downtracks_raw_line2 = carma_wm::geometry::compute_arc_lengths(line_2);
516 //TODO: unused variable: int total_step_along_curve2 = static_cast<int>(downtracks_raw_line2.back() / 2.0);
517 //TODO: unused variable: double step_threshold_line2 = (double)total_step_along_curve2 / (double)total_point_size;
518
519 double scaled_steps_along_curve = 0.0; // from 0 (start) to 1 (end) for the whole trajectory
520
521
522 all_sampling_points_line2.reserve(1 + total_point_size * 2);
523
524 for(size_t i = 0;i<total_point_size; ++i){
525 lanelet::BasicPoint2d p1 = (*fit_curve_1)(scaled_steps_along_curve);
526 lanelet::BasicPoint2d p2 = (*fit_curve_2)(scaled_steps_along_curve);
527 all_sampling_points_line1.push_back(p1);
528 all_sampling_points_line2.push_back(p2);
529
530 scaled_steps_along_curve += 1.0 / total_point_size; //adding steps_along_curve_step_size
531 }
532
533 output.push_back(all_sampling_points_line1);
534 output.push_back(all_sampling_points_line2);
535
536 auto end_time = std::chrono::high_resolution_clock::now();
537
538 auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time);
539 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "ExecutionTime for resample lane change centerlines: " << duration.count() << " milliseconds");
540
541 return output;
542 }

References BASIC_AUTONOMY_LOGGER, carma_wm::geometry::compute_arc_lengths(), compute_fit(), and process_bag::i.

Referenced by create_lanechange_geometry().

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

◆ split_point_speed_pairs()

void basic_autonomy::waypoint_generation::split_point_speed_pairs ( const std::vector< PointSpeedPair > &  points,
std::vector< lanelet::BasicPoint2d > *  basic_points,
std::vector< double > *  speeds 
)

Helper method to split a list of PointSpeedPair into separate point and speed lists.

Parameters
pointsPoint Speed pair to split
basic_pointspoints vector to be filled
speedsspeeds vector to be filled

Definition at line 92 of file helper_functions.cpp.

95 {
96 basic_points->reserve(points.size());
97 speeds->reserve(points.size());
98
99 for (const auto& p : points)
100 {
101 basic_points->push_back(p.point);
102 speeds->push_back(p.speed);
103 }
104 }

Referenced by compose_lanechange_trajectory_from_path(), compose_lanefollow_trajectory_from_path(), stop_controlled_intersection_tactical_plugin::StopControlledIntersectionTacticalPlugin::compose_trajectory_from_centerline(), constrain_to_time_boundary(), and get_nearest_index_by_downtrack().

Here is the caller graph for this function:

◆ trajectory_from_points_times_orientations()

std::vector< carma_planning_msgs::msg::TrajectoryPlanPoint > basic_autonomy::waypoint_generation::trajectory_from_points_times_orientations ( const std::vector< lanelet::BasicPoint2d > &  points,
const std::vector< double > &  times,
const std::vector< double > &  yaws,
rclcpp::Time  startTime,
const std::string &  desired_controller_plugin 
)

Method combines input points, times, orientations, and an absolute start time to form a valid carma platform trajectory.

NOTE: All input vectors must be the same size. The output vector will take this size.

Parameters
pointsThe points in the map frame that the trajectory will follow. Units m
timesThe times which at the vehicle should arrive at the specified points. First point should have a value of 0. Units s
yawsThe orientation the vehicle should achieve at each point. Units radians
startTimeThe absolute start time which will be used to update the input relative times. Units s
desired_controller_pluginThe name of the controller plugin for the generated trajectory.
Returns
A list of trajectory points built from the provided inputs.

Definition at line 762 of file basic_autonomy.cpp.

765 {
766 if (points.size() != times.size() || points.size() != yaws.size())
767 {
768 throw std::invalid_argument("All input vectors must have the same size");
769 }
770
771 std::vector<carma_planning_msgs::msg::TrajectoryPlanPoint> traj;
772 traj.reserve(points.size());
773
774 for (size_t i = 0; i < points.size(); i++)
775 {
776 carma_planning_msgs::msg::TrajectoryPlanPoint tpp;
777 rclcpp::Duration relative_time(times[i] * 1e9); // Conversion of times[i] from seconds to nanoseconds
778 tpp.target_time = startTime + relative_time;
779 tpp.x = points[i].x();
780 tpp.y = points[i].y();
781 tpp.yaw = yaws[i];
782
783 tpp.controller_plugin_name = desired_controller_plugin;
784 //tpp.planner_plugin_name //Planner plugin name is filled in the tactical plugin
785
786 traj.push_back(tpp);
787 }
788
789 return traj;
790 }

References process_bag::i.

Referenced by compose_lanechange_trajectory_from_path(), compose_lanefollow_trajectory_from_path(), and stop_controlled_intersection_tactical_plugin::StopControlledIntersectionTacticalPlugin::compose_trajectory_from_centerline().

Here is the caller graph for this function:

Variable Documentation

◆ BASIC_AUTONOMY_LOGGER

◆ epsilon_

const double basic_autonomy::waypoint_generation::epsilon_ = 0.0000001

Definition at line 24 of file helper_functions.hpp.

Referenced by add_lanefollow_buffer().