Carma-platform v4.11.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::vector< carma_planning_msgs::msg::TrajectoryPlanPoint > constrain_to_time_boundary (const std::vector< carma_planning_msgs::msg::TrajectoryPlanPoint > &trajectory, 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...
 
size_t get_nearest_point_index (const std::vector< carma_planning_msgs::msg::TrajectoryPlanPoint > &trajectory, const lanelet::BasicPoint2d &position)
 Find the index of the closest trajectory plan point to a given position. 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...
 
std::vector< lanelet::BasicPoint2d > build_chain_centerline (const carma_wm::WorldModelConstPtr &wm, lanelet::ConstLanelet pivot, double backward_length, double forward_length)
 Builds a centerline covering [pivot_end_point - backward_length, pivot_end_point + forward_length] by walking the pivot lanelet's own predecessor/successor chain in the routing graph. More...
 
void extrapolate_to_length (std::vector< lanelet::BasicPoint2d > &centerline, double target_length, const std::string &description)
 Pads a centerline out to target_length by extrapolating a straight line from its last known heading, if map connectivity could not supply enough real geometry (e.g. because a lanelet the lane change needed was closed or missing from the map). 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 1316 of file basic_autonomy.cpp.

1317 { // Note first speed is assumed to be vehicle speed
1318 if (speeds.size() != downtracks.size()) {
1319 throw std::invalid_argument("Speed list and downtrack list are not the same size.");
1320 }
1321
1322 std::vector<double> output;
1323 if (speeds.empty()) {
1324 return output;
1325 }
1326
1327 double lookahead_distance = speeds[0] * response_lag;
1328
1329 double downtrack_cutoff = downtracks[0] + lookahead_distance;
1330 size_t lookahead_count = std::lower_bound(downtracks.begin(),downtracks.end(), downtrack_cutoff) - downtracks.begin(); // Use binary search to find lower bound cutoff point
1331 output = trajectory_utils::shift_by_lookahead(speeds, (unsigned int) lookahead_count);
1332 return output;
1333 }

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 541 of file basic_autonomy.cpp.

543 {
544 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Speeds list size: " << speeds.size());
545 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "SpeedLimits list size: " << speed_limits.size());
546
547 if (speeds.size() != speed_limits.size())
548 {
549 throw std::invalid_argument("Speeds and speed limit lists not same size");
550 }
551 std::vector<double> out;
552 for (size_t i = 0; i < speeds.size(); i++)
553 {
554 out.push_back(std::min(speeds[i], speed_limits[i]));
555 }
556
557 return out;
558 }

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 759 of file basic_autonomy.cpp.

761 {
762 std::vector<PointSpeedPair> back_and_future;
763 back_and_future.reserve(points_set.size());
764 double total_dist = 0;
765 int min_i = 0;
766
767 // int must be used here to avoid overflow when i = 0
768 for (int i = nearest_pt_index; i >= 0; --i)
769 {
770 min_i = i;
771 total_dist += lanelet::geometry::distance2d(points_set[i].point, points_set[i - 1].point);
772
773 if (total_dist > back_distance)
774 {
775 break;
776 }
777 }
778
779 back_and_future.insert(back_and_future.end(), points_set.begin() + min_i, points_set.begin() + nearest_pt_index + 1);
780 back_and_future.insert(back_and_future.end(), future_points.begin(), future_points.end());
781 return back_and_future;
782 }

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:

◆ build_chain_centerline()

std::vector< lanelet::BasicPoint2d > basic_autonomy::waypoint_generation::build_chain_centerline ( const carma_wm::WorldModelConstPtr wm,
lanelet::ConstLanelet  pivot,
double  backward_length,
double  forward_length 
)

Builds a centerline covering [pivot_end_point - backward_length, pivot_end_point + forward_length] by walking the pivot lanelet's own predecessor/successor chain in the routing graph.

If the routing graph runs out of connected lanelets before reaching the requested length (e.g. a closed lanelet blocks further routing), this logs a warning and returns whatever centerline was actually reachable instead of throwing – the caller is responsible for padding the result out if a minimum length is required (see extrapolate_to_length below).

Parameters
wmThe carma world model, used to query the map's routing graph
pivotThe lanelet to build the centerline outward from
backward_lengthThe minimum distance the returned centerline must cover behind the end of pivot, gathered by walking pivot's predecessor chain
forward_lengthThe minimum distance the returned centerline must cover beyond the end of pivot, gathered by walking pivot's successor chain
Returns
The concatenated 2d centerline points of pivot and however many predecessor/successor lanelets were needed (and reachable) to satisfy backward_length and forward_length

Definition at line 147 of file helper_functions.cpp.

151 {
152 std::vector<lanelet::ConstLanelet> chain{pivot};
153 std::unordered_set<lanelet::Id> visited{pivot.id()};
154
155 double covered_back = carma_wm::geometry::get_lanelet_centerline_length(pivot);
156 while (covered_back < backward_length)
157 {
158 auto previous = wm->getMapRoutingGraph()->previous(chain.front(), false);
159 bool no_predecessor = previous.empty();
160 bool loop_detected = !no_predecessor && visited.count(previous.front().id()) > 0;
161
162 if (no_predecessor)
163 {
164 RCLCPP_WARN_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER),
165 "create_lanechange_geometry: No routable predecessor lanelet found before lanelet "
166 << chain.front().id() << " (possibly closed or missing from the map). Using the "
167 << covered_back << "m of centerline that was reachable going backward.");
168 }
169
170 if (loop_detected)
171 {
172 RCLCPP_WARN_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER),
173 "create_lanechange_geometry: Detected a loop in lanelet connectivity before lanelet "
174 << chain.front().id() << "; stopping centerline extension.");
175 }
176
177 if (no_predecessor || loop_detected)
178 {
179 break;
180 }
181
182 lanelet::ConstLanelet prev = previous.front();
183 visited.insert(prev.id());
185 chain.insert(chain.begin(), prev);
186 }
187
188 double covered_fwd = 0.0;
189 while (covered_fwd < forward_length)
190 {
191 auto following = wm->getMapRoutingGraph()->following(chain.back(), false);
192 bool no_successor = following.empty();
193 bool loop_detected = !no_successor && visited.count(following.front().id()) > 0;
194
195 if (no_successor)
196 {
197 RCLCPP_WARN_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER),
198 "create_lanechange_geometry: No routable successor lanelet found after lanelet "
199 << chain.back().id() << " (possibly closed or missing from the map). Using the "
200 << covered_fwd << "m of centerline that was reachable going forward.");
201 }
202
203 if (loop_detected)
204 {
205 RCLCPP_WARN_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER),
206 "create_lanechange_geometry: Detected a loop in lanelet connectivity after lanelet "
207 << chain.back().id() << "; stopping centerline extension.");
208 }
209
210 if (no_successor || loop_detected)
211 {
212 break;
213 }
214
215 lanelet::ConstLanelet next = following.front();
216 visited.insert(next.id());
218 chain.push_back(next);
219 }
220
221 std::vector<lanelet::BasicPoint2d> centerline;
222 centerline.reserve(400);
223 for (size_t i = 0; i < chain.size(); ++i)
224 {
225 auto ls = chain[i].centerline2d().basicLineString();
226 if (i == 0)
227 {
228 centerline.insert(centerline.end(), ls.begin(), ls.end());
229 }
230 else
231 {
232 // Concatenate linestring starting from + 1 to avoid duplicating the shared endpoint
233 centerline.insert(centerline.end(), ls.begin() + 1, ls.end());
234 }
235 }
236 return centerline;
237 }
double get_lanelet_centerline_length(const lanelet::ConstLanelet &ll)
Returns the total 2d arc length of a lanelet's centerline.
Definition: Geometry.cpp:504

References BASIC_AUTONOMY_LOGGER, carma_wm::geometry::get_lanelet_centerline_length(), 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:

◆ 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 1057 of file basic_autonomy.cpp.

1067 {
1068 DetailedTrajConfig detailed_config;
1069
1070 detailed_config.trajectory_time_length = trajectory_time_length;
1071 detailed_config.curve_resample_step_size = curve_resample_step_size;
1072 detailed_config.minimum_speed = minimum_speed;
1073 detailed_config.max_accel = max_accel;
1074 detailed_config.lateral_accel_limit = lateral_accel_limit;
1075 detailed_config.speed_moving_average_window_size = speed_moving_average_window_size;
1076 detailed_config.curvature_moving_average_window_size = curvature_moving_average_window_size;
1077 detailed_config.back_distance = back_distance;
1078 detailed_config.buffer_ending_downtrack = buffer_ending_downtrack;
1079 detailed_config.desired_controller_plugin = desired_controller_plugin;
1080
1081 return detailed_config;
1082 }

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 light_controlled_intersection_tactical_plugin::LightControlledIntersectionTacticalPlugin::generateNewTrajectory(), cooperative_lanechange::CooperativeLaneChangePlugin::plan_lanechange(), inlanecruising_plugin::InLaneCruisingPlugin::plan_trajectory_callback(), and platooning_tactical_plugin::PlatooningTacticalPlugin::plan_trajectory_cb().

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 1099 of file basic_autonomy.cpp.

1102 {
1103 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Input points size in compose traj from centerline: "<< points.size());
1104 int nearest_pt_index = get_nearest_index_by_downtrack(points, wm, state);
1105 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "nearest_pt_index: "<< nearest_pt_index);
1106
1107 std::vector<PointSpeedPair> future_points(points.begin() + nearest_pt_index + 1, points.end());
1108 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "future_points size: "<< future_points.size());
1109
1110 //Compute yaw values from original trajectory.
1111 std::vector<lanelet::BasicPoint2d> future_geom_points;
1112 std::vector<double> final_actual_speeds;
1113 split_point_speed_pairs(future_points, &future_geom_points, &final_actual_speeds);
1114
1115 std::unique_ptr<smoothing::SplineI> fit_curve = compute_fit(future_geom_points);
1116 if(!fit_curve){
1117 throw std::invalid_argument("Could not fit a spline curve along the given trajectory!");
1118 }
1119 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Got fit");
1120
1121 // Add current vehicle position to front of future geometry points
1122 lanelet::BasicPoint2d current_vehicle_point(state.x_pos_global, state.y_pos_global);
1123 future_geom_points.insert(future_geom_points.begin(), current_vehicle_point);
1124 final_actual_speeds.insert(final_actual_speeds.begin(), state.longitudinal_vel);
1125
1126 // Compute downtracks for original points (for interpolation reference)
1127 std::vector<double> original_downtracks = carma_wm::geometry::compute_arc_lengths(future_geom_points);
1128
1129 // Now create resampled points using the spline
1130 auto total_step_along_curve = static_cast<int>(original_downtracks.back() / detailed_config.curve_resample_step_size);
1131 if (total_step_along_curve == 0) {
1132 RCLCPP_WARN_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER),
1133 "Available distance to resample is less than curve_resample_step_size. "
1134 "Only considering the last point of the target destination to generate trajectory."
1135 );
1136 total_step_along_curve = 1; // This also avoids division by zero
1137 }
1138
1139 std::vector<lanelet::BasicPoint2d> resampled_points;
1140 resampled_points.reserve(total_step_along_curve + 1);
1141
1142 double scaled_steps_along_curve = 0.0; // from 0 (start) to 1 (end) for the whole trajectory
1143 for(int step = 0; step <= total_step_along_curve; step++){
1144 scaled_steps_along_curve = static_cast<double>(step) / total_step_along_curve;
1145 lanelet::BasicPoint2d p = (*fit_curve)(scaled_steps_along_curve);
1146 resampled_points.push_back(p);
1147 }
1148 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Got resampled points with size:" << resampled_points.size());
1149
1150 // Compute downtracks for the resampled points
1151 std::vector<double> resampled_downtracks = carma_wm::geometry::compute_arc_lengths(resampled_points);
1152
1153 // Interpolate speeds based on downtracks
1154 std::vector<double> resampled_speeds;
1155 resampled_speeds.reserve(resampled_points.size());
1156
1157 for (const auto& downtrack : resampled_downtracks) {
1158 // Find where this downtrack would fit in the original downtracks
1159 auto it = std::upper_bound(original_downtracks.begin(), original_downtracks.end(), downtrack);
1160 size_t idx = it - original_downtracks.begin();
1161
1162 if (idx == 0) {
1163 // Point is before first point, use first speed
1164 resampled_speeds.push_back(final_actual_speeds[0]);
1165 } else if (idx >= original_downtracks.size()) {
1166 // Point is after last point, use last speed
1167 resampled_speeds.push_back(final_actual_speeds.back());
1168 } else {
1169 // Approximating the speed to the original because moving average filter
1170 // will smooth the speed values anyways
1171 resampled_speeds.push_back(final_actual_speeds[idx]);
1172 }
1173 }
1174
1175 // Apply the moving average filter to the resampled speeds
1176 resampled_speeds = smoothing::moving_average_filter(resampled_speeds, detailed_config.speed_moving_average_window_size);
1177
1178 // Compute yaw values based on the resampled points
1179 std::vector<double> resampled_yaw_values = carma_wm::geometry::compute_tangent_orientations(resampled_points);
1180 if (!resampled_yaw_values.empty())
1181 {
1182 resampled_yaw_values[0] = state.orientation; // Set the initial yaw value based on the initial state
1183 }
1184
1185 // Convert speeds to time
1186 std::vector<double> times;
1187 trajectory_utils::conversions::speed_to_time(resampled_downtracks, resampled_speeds, &times);
1188
1189 //Remove extra points
1190 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Before removing extra buffer points, future_geom_points.size()"<< future_geom_points.size());
1191
1192 // Find the ending point index in the resampled points
1193 // Always leave at least 2 points in the trajectory
1194 // NOTE: resampled_points.size() is always >= 2 because
1195 // we added the current vehicle position and the division of 0 guard before
1196 int end_dist_pt_index =
1198 resampled_points, wm, ending_state_before_buffer)
1199 );
1200
1201 // Resize all arrays to the endpoint
1202 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Before removing extra buffer points, resampled_points.size(): " << resampled_points.size());
1203 resampled_points.resize(end_dist_pt_index + 1);
1204 times.resize(end_dist_pt_index + 1);
1205 resampled_yaw_values.resize(end_dist_pt_index + 1);
1206 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "After removing extra buffer points, resampled_points.size(): " << resampled_points.size());
1207
1208 // Create trajectory points from the resampled data
1209 std::vector<carma_planning_msgs::msg::TrajectoryPlanPoint> traj_points =
1210 trajectory_from_points_times_orientations(resampled_points, times, resampled_yaw_values, state_time, detailed_config.desired_controller_plugin);
1211
1212 return traj_points;
1213 }
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:565
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 840 of file basic_autonomy.cpp.

843 {
844 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "VehicleState: "
845 << " x: " << state.x_pos_global << " y: " << state.y_pos_global << " yaw: " << state.orientation
846 << " speed: " << state.longitudinal_vel);
847
849
850 int nearest_pt_index = get_nearest_point_index(points, state);
851
852 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "NearestPtIndex: " << nearest_pt_index);
853
854 std::vector<PointSpeedPair> future_points(points.begin() + nearest_pt_index + 1, points.end()); // Points in front of current vehicle position
855
856 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);
857
858 auto time_bound_points = constrain_to_time_boundary(future_points, detailed_config.trajectory_time_length);
859
860 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Got time_bound_points with size:" << time_bound_points.size());
862
863 std::vector<PointSpeedPair> back_and_future = attach_past_points(points, time_bound_points, nearest_pt_index, detailed_config.back_distance);
864
865 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Got back_and_future points with size" << back_and_future.size());
867
868 std::vector<double> speed_limits;
869 std::vector<lanelet::BasicPoint2d> curve_points;
870 split_point_speed_pairs(back_and_future, &curve_points, &speed_limits);
871
872 std::unique_ptr<smoothing::SplineI> fit_curve = compute_fit(curve_points); // Compute splines based on curve points
873 if (!fit_curve)
874 {
875 throw std::invalid_argument("Could not fit a spline curve along the given trajectory!");
876 }
877
878 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Got fit");
879
880 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "speed_limits.size() " << speed_limits.size());
881
882 std::vector<lanelet::BasicPoint2d> all_sampling_points;
883 all_sampling_points.reserve(1 + curve_points.size() * 2);
884
885 std::vector<double> distributed_speed_limits;
886 distributed_speed_limits.reserve(1 + curve_points.size() * 2);
887
888 // compute total length of the trajectory to get correct number of points
889 // we expect using curve_resample_step_size
890 std::vector<double> downtracks_raw = carma_wm::geometry::compute_arc_lengths(curve_points);
891
892 auto total_step_along_curve = static_cast<int>(downtracks_raw.back() / detailed_config.curve_resample_step_size);
893
894 int current_speed_index = 0;
895 size_t total_point_size = curve_points.size();
896
897 double step_threshold_for_next_speed = (double)total_step_along_curve / (double)total_point_size;
898 double scaled_steps_along_curve = 0.0; // from 0 (start) to 1 (end) for the whole trajectory
899 std::vector<double> better_curvature;
900 better_curvature.reserve(1 + curve_points.size() * 2);
901
902 for (int steps_along_curve = 0; steps_along_curve < total_step_along_curve; steps_along_curve++) // Resample curve at tighter resolution
903 {
904 lanelet::BasicPoint2d p = (*fit_curve)(scaled_steps_along_curve);
905
906 all_sampling_points.push_back(p);
907 double c = compute_curvature_at((*fit_curve), scaled_steps_along_curve);
908 better_curvature.push_back(c);
909 if ((double)steps_along_curve > step_threshold_for_next_speed)
910 {
911 step_threshold_for_next_speed += (double)total_step_along_curve / (double)total_point_size;
912 current_speed_index++;
913 }
914 distributed_speed_limits.push_back(speed_limits[current_speed_index]); // Identify speed limits for resampled points
915 scaled_steps_along_curve += 1.0 / total_step_along_curve; //adding steps_along_curve_step_size
916 }
917
918 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Got sampled points with size:" << all_sampling_points.size());
919 log::printDebugPerLine(all_sampling_points, &log::basicPointToStream);
920
921 std::vector<double> final_yaw_values = carma_wm::geometry::compute_tangent_orientations(all_sampling_points);
922
923 log::printDoublesPerLineWithPrefix("raw_curvatures[i]: ", better_curvature);
924
925 std::vector<double> curvatures = smoothing::moving_average_filter(better_curvature, detailed_config.curvature_moving_average_window_size, false);
926 std::vector<double> ideal_speeds =
927 trajectory_utils::constrained_speeds_for_curvatures(curvatures, detailed_config.lateral_accel_limit);
928
929 log::printDoublesPerLineWithPrefix("curvatures[i]: ", curvatures);
930 log::printDoublesPerLineWithPrefix("ideal_speeds: ", ideal_speeds);
931 log::printDoublesPerLineWithPrefix("final_yaw_values[i]: ", final_yaw_values);
932
933 std::vector<double> constrained_speed_limits = apply_speed_limits(ideal_speeds, distributed_speed_limits);
934
935 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Processed all points in computed fit");
936
937 if (all_sampling_points.empty())
938 {
939 RCLCPP_WARN_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "No trajectory points could be generated");
940 return {};
941 }
942
943 // Add current vehicle point to front of the trajectory
944
945 nearest_pt_index = get_nearest_index_by_downtrack(all_sampling_points, wm, state);
946 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Current state's nearest_pt_index: " << nearest_pt_index);
947 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);
948 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());
949
950 int buffer_pt_index = get_nearest_index_by_downtrack(all_sampling_points, wm, ending_state_before_buffer);
951 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Ending state's index before applying buffer (buffer_pt_index): " << buffer_pt_index);
952 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());
953
954 if(nearest_pt_index + 1 >= buffer_pt_index){
955
956 lanelet::BasicPoint2d current_pos(state.x_pos_global, state.y_pos_global);
957 lanelet::BasicPoint2d ending_pos(ending_state_before_buffer.x_pos_global, ending_state_before_buffer.y_pos_global);
958
959 if(wm->routeTrackPos(ending_pos).downtrack < wm->routeTrackPos(current_pos).downtrack ){
960
961 RCLCPP_WARN_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Current state is at or past the planned end distance. Couldn't generate trajectory");
962 return {};
963 }
964 else{
965 //Current point is behind the ending state of maneuver and a valid trajectory is possible
966 RCLCPP_WARN_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Returning the two remaining points in the maneuver");
967
968 std::vector<lanelet::BasicPoint2d> remaining_traj_points = {current_pos, ending_pos};
969
970 std::vector<double> downtracks = carma_wm::geometry::compute_arc_lengths(remaining_traj_points);
971 std::vector<double> speeds = {state.longitudinal_vel, state.longitudinal_vel};//Keep current speed
972 std::vector<double> times;
973 trajectory_utils::conversions::speed_to_time(downtracks, speeds, &times);
974 std::vector<double> yaw = {state.orientation, state.orientation}; //Keep current orientation
975
976 std::vector<carma_planning_msgs::msg::TrajectoryPlanPoint> traj_points =
977 trajectory_from_points_times_orientations(remaining_traj_points, times, yaw, state_time, detailed_config.desired_controller_plugin);
978
979 return traj_points;
980
981 }
982 }
983
984 //drop buffer points here
985
986 std::vector<lanelet::BasicPoint2d> future_basic_points(all_sampling_points.begin() + nearest_pt_index + 1,
987 all_sampling_points.begin()+ buffer_pt_index); // Points in front of current vehicle position
988
989 std::vector<double> future_speeds(constrained_speed_limits.begin() + nearest_pt_index + 1,
990 constrained_speed_limits.begin() + buffer_pt_index); // Points in front of current vehicle position
991 std::vector<double> future_yaw(final_yaw_values.begin() + nearest_pt_index + 1,
992 final_yaw_values.begin() + buffer_pt_index); // Points in front of current vehicle position
993 std::vector<double> final_actual_speeds = future_speeds;
994 all_sampling_points = future_basic_points;
995 final_yaw_values = future_yaw;
996 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Trimmed future points to size: "<< future_basic_points.size());
997
998 lanelet::BasicPoint2d cur_veh_point(state.x_pos_global, state.y_pos_global);
999
1000 all_sampling_points.insert(all_sampling_points.begin(),
1001 cur_veh_point); // Add current vehicle position to front of sample points
1002
1003 final_actual_speeds.insert(final_actual_speeds.begin(), state.longitudinal_vel);
1004
1005 final_yaw_values.insert(final_yaw_values.begin(), state.orientation);
1006
1007 // Compute points to local downtracks
1008 std::vector<double> downtracks = carma_wm::geometry::compute_arc_lengths(all_sampling_points);
1009
1010 // Apply accel limits
1011 final_actual_speeds = optimize_speed(downtracks, final_actual_speeds, detailed_config.max_accel);
1012
1013 log::printDoublesPerLineWithPrefix("postAccel[i]: ", final_actual_speeds);
1014
1015 final_actual_speeds = smoothing::moving_average_filter(final_actual_speeds, detailed_config.speed_moving_average_window_size);
1016
1017 log::printDoublesPerLineWithPrefix("post_average[i]: ", final_actual_speeds);
1018
1019 for (auto &s : final_actual_speeds) // Limit minimum speed. TODO how to handle stopping?
1020 {
1021 s = std::max(s, detailed_config.minimum_speed);
1022 }
1023
1024 log::printDoublesPerLineWithPrefix("post_min_speed[i]: ", final_actual_speeds);
1025
1026 // Convert speeds to times
1027 std::vector<double> times;
1028 trajectory_utils::conversions::speed_to_time(downtracks, final_actual_speeds, &times);
1029
1030 log::printDoublesPerLineWithPrefix("times[i]: ", times);
1031
1032 // Build trajectory points
1033 std::vector<carma_planning_msgs::msg::TrajectoryPlanPoint> traj_points =
1034 trajectory_from_points_times_orientations(all_sampling_points, times, final_yaw_values, state_time, detailed_config.desired_controller_plugin);
1035
1036 //debug msg
1037 carma_debug_ros2_msgs::msg::TrajectoryCurvatureSpeeds msg;
1038 msg.velocity_profile = final_actual_speeds;
1039 msg.relative_downtrack = downtracks;
1040 msg.tangent_headings = final_yaw_values;
1041 std::vector<double> aligned_speed_limits(constrained_speed_limits.begin() + nearest_pt_index,
1042 constrained_speed_limits.end());
1043
1044 msg.speed_limits = aligned_speed_limits;
1045 std::vector<double> aligned_curvatures(curvatures.begin() + nearest_pt_index,
1046 curvatures.end());
1047 msg.curvatures = aligned_curvatures;
1048 msg.lat_accel_limit = detailed_config.lateral_accel_limit;
1049 msg.lon_accel_limit = detailed_config.max_accel;
1050 msg.starting_state = state;
1051 debug_msg = msg;
1052
1053
1054 return traj_points;
1055 }
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, osm_transform::x, and osm_transform::y.

Referenced by light_controlled_intersection_tactical_plugin::LightControlledIntersectionTacticalPlugin::generateNewTrajectory(), 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:

◆ 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 830 of file basic_autonomy.cpp.

831 {
832 lanelet::BasicPoint2d f_prime_pt = fit_curve.first_deriv(step_along_the_curve);
833 lanelet::BasicPoint2d f_prime_prime_pt = fit_curve.second_deriv(step_along_the_curve);
834 // Convert to 3d vector to do 3d vector operations like cross.
835 Eigen::Vector3d f_prime = {f_prime_pt.x(), f_prime_pt.y(), 0};
836 Eigen::Vector3d f_prime_prime = {f_prime_prime_pt.x(), f_prime_prime_pt.y(), 0};
837 return (f_prime.cross(f_prime_prime)).norm() / (pow(f_prime.norm(), 3));
838 }
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 784 of file basic_autonomy.cpp.

785 {
786 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Original basic_points size: " << basic_points.size());
787
788 // When computing fit, there cannot be duplicate points or points less than 0.5 meters apart.
789 // Therefore, this function generally cleans the points for robust spline fit.
790 auto points_with_min_dis = downsample_pts_with_min_meters
791 <std::vector<lanelet::BasicPoint2d>>(basic_points);
792
793 if (points_with_min_dis.size() < 4)
794 {
795 RCLCPP_WARN_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Insufficient Spline Points");
796 return nullptr;
797 }
798
799 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "points_with_min_dis size: " << points_with_min_dis.size());
800
801 std::vector<lanelet::BasicPoint2d> resized_points_with_min_dis = points_with_min_dis;
802
803 // The large the number of points, longer it takes to calculate a spline fit
804 // So if the basic_points vector size is large, only the first 400 points are used to compute a spline fit.
805 if (resized_points_with_min_dis.size() > 400)
806 {
807 resized_points_with_min_dis.resize(400);
808 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "resized_points_with_min_dis size: " << resized_points_with_min_dis.size());
809
810 size_t left_points_size = points_with_min_dis.size() - resized_points_with_min_dis.size();
811 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Left out points size: " << left_points_size);
812
813 float percent_points_lost = 100.0f
814 * static_cast<float>(left_points_size) /
815 static_cast<float>(points_with_min_dis.size());
816
817 if (percent_points_lost > 50.0)
818 {
819 RCLCPP_WARN_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "More than half of basic points are ignored for spline fitting");
820 }
821 }
822
823 std::unique_ptr<basic_autonomy::smoothing::SplineI> spl = std::make_unique<basic_autonomy::smoothing::BSpline>();
824
825 spl->setPoints(resized_points_with_min_dis);
826
827 return spl;
828 }

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 560 of file basic_autonomy.cpp.

562 {
563 Eigen::Rotation2Dd yaw(atan2(p2.y() - p1.y(), p2.x() - p1.x()));
564
566 }
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:576

References carma_wm::geometry::build2dEigenTransform().

Here is the call graph for this function:

◆ constrain_to_time_boundary() [1/2]

std::vector< carma_planning_msgs::msg::TrajectoryPlanPoint > basic_autonomy::waypoint_generation::constrain_to_time_boundary ( const std::vector< carma_planning_msgs::msg::TrajectoryPlanPoint > &  trajectory,
double  time_span 
)

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

Parameters
trajectoryThe input trajectory plan point each with target_time
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 568 of file basic_autonomy.cpp.

571 {
572 if (trajectory.empty())
573 {
574 RCLCPP_WARN_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER),
575 "constrain_to_time_boundary received empty trajectory, returning...");
576 return trajectory;
577 }
578
579 if (time_span <= 0)
580 {
581 RCLCPP_WARN_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER),
582 "constrain_to_time_boundary received non-positive time span, returning...");
583 return trajectory;
584 }
585
586 // return immediately if the trajectory is already within the time span
587 if ((rclcpp::Time(trajectory.back().target_time) -
588 rclcpp::Time(trajectory.front().target_time)).seconds() <= time_span)
589 {
590 return trajectory;
591 }
592
593 // find the first point that is outside the time span
594 std::vector<carma_planning_msgs::msg::TrajectoryPlanPoint> constrained_points;
595 auto start_time = rclcpp::Time(trajectory.front().target_time);
596 auto end_time = start_time + rclcpp::Duration::from_seconds(time_span);
597 for (const auto& tpp : trajectory)
598 {
599 if (rclcpp::Time(tpp.target_time) > end_time)
600 {
601 break;
602 }
603 constrained_points.push_back(tpp);
604 }
605
606 return constrained_points;
607 }

References BASIC_AUTONOMY_LOGGER.

◆ constrain_to_time_boundary() [2/2]

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 609 of file basic_autonomy.cpp.

611 {
612 std::vector<lanelet::BasicPoint2d> basic_points;
613 std::vector<double> speeds;
614 split_point_speed_pairs(points, &basic_points, &speeds);
615
616 std::vector<double> downtracks = carma_wm::geometry::compute_arc_lengths(basic_points);
617
618 size_t time_boundary_exclusive_index =
619 trajectory_utils::time_boundary_index(downtracks, speeds, time_span);
620
621 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "time_boundary_exclusive_index = " << time_boundary_exclusive_index);
622
623 if (time_boundary_exclusive_index == 0)
624 {
625 throw std::invalid_argument("No points to fit in timespan");
626 }
627
628 std::vector<PointSpeedPair> time_bound_points;
629 time_bound_points.reserve(time_boundary_exclusive_index);
630
631 if (time_boundary_exclusive_index == points.size())
632 {
633 time_bound_points.insert(time_bound_points.end(), points.begin(),
634 points.end()); // All points fit within time boundary
635 }
636 else
637 {
638 time_bound_points.insert(time_bound_points.end(), points.begin(),
639 points.begin() + time_boundary_exclusive_index - 1); // Limit points by time boundary
640 }
641
642 return time_bound_points;
643 }

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

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

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 double lane_change_length = ending_downtrack - starting_downtrack;
329
330 // Build the starting-lane (reference) and ending-lane (target) centerlines independently, each from its
331 // own lanelet's predecessor/successor chain. See build_chain_centerline's doc comment for why this is
332 // done instead of looking up "the lanelet adjacent to X" for every lanelet along the starting lane path.
333 // NOTE: starting_lanelet may NOT be the lanechange lanelets in the route, but could be
334 // little before due to accounting for front bumper in plan_delegator.
335 std::vector<lanelet::BasicPoint2d> reference_centerline =
336 build_chain_centerline(wm, starting_lanelet, 0.0, lane_change_length + buffer_ending_downtrack);
337 std::vector<lanelet::BasicPoint2d> target_lane_centerline =
338 build_chain_centerline(wm, ending_lanelet, lane_change_length, buffer_ending_downtrack);
339
340 // If the map didn't have enough connected/routable lanelets to reach the required length (for example a
341 // closed lanelet blocked further routing), pad the centerlines out with a straight-line extrapolation
342 // instead of failing -- see extrapolate_to_length's doc comment.
343 extrapolate_to_length(reference_centerline, lane_change_length + buffer_ending_downtrack, "starting lanelet " + std::to_string(starting_lane_id) + "'s lane");
344 extrapolate_to_length(target_lane_centerline, lane_change_length + buffer_ending_downtrack, "ending lanelet " + std::to_string(ending_lane_id) + "'s lane");
345
346 //Downsample centerlines
347 // 400 value here is an arbitrary attempt at improving performance by reducing copy operations.
348 // Value picked based on annecdotal evidence from STOL system testing
349
350 std::vector<lanelet::BasicPoint2d> downsampled_starting_centerline;
351 downsampled_starting_centerline.reserve(400);
352 downsampled_starting_centerline = carma_ros2_utils::containers::downsample_vector(reference_centerline, downsample_ratio);
353
354 std::vector<lanelet::BasicPoint2d> downsampled_target_centerline;
355 downsampled_target_centerline.reserve(400);
356 downsampled_target_centerline = carma_ros2_utils::containers::downsample_vector(target_lane_centerline, downsample_ratio);
357
358 // Constrain centerlines to starting and ending downtrack
359 int start_index_starting_centerline = waypoint_generation::get_nearest_index_by_downtrack(downsampled_starting_centerline, wm, starting_downtrack);
360 carma_planning_msgs::msg::VehicleState start_state;
361 start_state.x_pos_global = downsampled_starting_centerline[start_index_starting_centerline].x();
362 start_state.y_pos_global = downsampled_starting_centerline[start_index_starting_centerline].y();
363 int start_index_target_centerline = waypoint_generation::get_nearest_point_index(downsampled_target_centerline, start_state);
364
365 int end_index_target_centerline = waypoint_generation::get_nearest_index_by_downtrack(downsampled_target_centerline, wm, ending_downtrack);
366 carma_planning_msgs::msg::VehicleState end_state;
367 end_state.x_pos_global = downsampled_target_centerline[end_index_target_centerline].x();
368 end_state.y_pos_global = downsampled_target_centerline[end_index_target_centerline].y();
369 int end_index_starting_centerline = waypoint_generation::get_nearest_point_index(downsampled_starting_centerline, end_state);
370
371 std::vector<lanelet::BasicPoint2d> constrained_start_centerline(downsampled_starting_centerline.begin() + start_index_starting_centerline, downsampled_starting_centerline.begin() + end_index_starting_centerline);
372 std::vector<lanelet::BasicPoint2d> constrained_target_centerline(downsampled_target_centerline.begin() + start_index_target_centerline, downsampled_target_centerline.begin() + end_index_target_centerline);
373
374 // If constrained centerlines are not the same size - resample to ensure same size along both centerlines
375 if(constrained_start_centerline.size() != constrained_target_centerline.size())
376 {
377 auto centerlines = resample_linestring_pair_to_same_size(constrained_start_centerline, constrained_target_centerline);
378 constrained_start_centerline = centerlines[0];
379 constrained_target_centerline = centerlines[1];
380 }
381
382 //Create Trajectory geometry
383 double delta_step = 1.0 / constrained_start_centerline.size();
384
385 for (size_t i = 0; i < constrained_start_centerline.size(); ++i)
386 {
387 lanelet::BasicPoint2d current_position;
388 lanelet::BasicPoint2d start_lane_pt = constrained_start_centerline[i];
389 lanelet::BasicPoint2d target_lane_pt = constrained_target_centerline[i];
390 double delta = delta_step * i;
391 current_position.x() = target_lane_pt.x() * delta + (1 - delta) * start_lane_pt.x();
392 current_position.y() = target_lane_pt.y() * delta + (1 - delta) * start_lane_pt.y();
393
394 centerline_points.push_back(current_position);
395 }
396
397 // Add points from the remaining length of the target lane to provide sufficient distance for the buffer.
398 // target_lane_centerline was already built out to lane_change_length + buffer_ending_downtrack by
399 // build_chain_centerline/extrapolate_to_length above (walking the target lane's own successor chain,
400 // with a straight-line fallback if the map ran out of routable lanelets), so no further lookup of
401 // "the lanelet following ending_lanelet" is needed here.
402 centerline_points.insert(centerline_points.end(), downsampled_target_centerline.begin() + end_index_target_centerline, downsampled_target_centerline.end());
403
404 return centerline_points;
405 }
void extrapolate_to_length(std::vector< lanelet::BasicPoint2d > &centerline, double target_length, const std::string &description)
Pads a centerline out to target_length by extrapolating a straight line from its last known heading,...
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.
std::vector< lanelet::BasicPoint2d > build_chain_centerline(const carma_wm::WorldModelConstPtr &wm, lanelet::ConstLanelet pivot, double backward_length, double forward_length)
Builds a centerline covering [pivot_end_point - backward_length, pivot_end_point + forward_length] by...
auto to_string(const UtmZone &zone) -> std::string
Definition: utm_zone.cpp:21

References build_chain_centerline(), extrapolate_to_length(), 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

◆ extrapolate_to_length()

void basic_autonomy::waypoint_generation::extrapolate_to_length ( std::vector< lanelet::BasicPoint2d > &  centerline,
double  target_length,
const std::string &  description 
)

Pads a centerline out to target_length by extrapolating a straight line from its last known heading, if map connectivity could not supply enough real geometry (e.g. because a lanelet the lane change needed was closed or missing from the map).

This is a last-resort fallback so that lane change trajectory generation always produces a usable result rather than throwing when the map has a gap – the extrapolated portion is only a straight-line approximation, but it lets the rest of the system (and, most importantly, the vehicle) keep moving instead of hitting an uncaught exception that stalls trajectory planning entirely.

Parameters
centerlineThe centerline to pad, in place, if it falls short of target_length
target_lengthThe minimum 2d arc length centerline must cover after this call
descriptionA human-readable description of what centerline represents, used in log/exception messages

Definition at line 239 of file helper_functions.cpp.

240 {
241 if (centerline.size() < 2)
242 {
243 throw std::invalid_argument("create_lanechange_geometry: " + description +
244 " has fewer than 2 centerline points; cannot build or extrapolate a lane change trajectory from this map data");
245 }
246
247 double current_length = carma_wm::geometry::compute_arc_lengths(centerline).back();
248 if (current_length >= target_length)
249 {
250 return;
251 }
252
253 RCLCPP_WARN_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER),
254 "create_lanechange_geometry: Only " << current_length << "m of connected lanelet centerline was "
255 << "available for " << description << " (needed " << target_length << "m). Extrapolating a "
256 << "straight line from the last known heading so a lane change trajectory can still be produced.");
257
258 lanelet::BasicPoint2d last = centerline.back();
259 lanelet::BasicPoint2d prev = centerline[centerline.size() - 2];
260 lanelet::BasicPoint2d direction = last - prev;
261 if (direction.norm() < 1e-6)
262 {
263 // Degenerate direction from the last segment; fall back to the vector from the first to last point
264 direction = last - centerline.front();
265 }
266 direction.normalize();
267
268 constexpr double step = 1.0; // meters between synthetic points, similar to typical map point spacing
269 double remaining = target_length - current_length;
270 for (int step_count = 1; step_count * step < remaining; ++step_count)
271 {
272 centerline.push_back(last + direction * (step_count * step));
273 }
274 centerline.push_back(last + direction * remaining); // ensure the full requested length is covered
275 }

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

Referenced by create_lanechange_geometry().

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

◆ 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 469 of file basic_autonomy.cpp.

472 {
473 if(maneuver.type != carma_planning_msgs::msg::Maneuver::LANE_CHANGE){
474 throw std::invalid_argument("Create_lanechange called on a maneuver type which is not LANE_CHANGE");
475 }
476 std::vector<PointSpeedPair> points_and_target_speeds;
477 std::unordered_set<lanelet::Id> visited_lanelets;
478
479 carma_planning_msgs::msg::LaneChangeManeuver lane_change_maneuver = maneuver.lane_change_maneuver;
480 double ending_downtrack = lane_change_maneuver.end_dist;
481 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Maneuver ending downtrack:"<<ending_downtrack);
482 if(starting_downtrack >= ending_downtrack)
483 {
484 throw(std::invalid_argument("Start distance is greater than or equal to ending distance"));
485 }
486
487 //get route between starting and ending downtracks - downtracks should be constant for complete length of maneuver
488 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),
489 starting_downtrack, ending_downtrack, wm, general_config.default_downsample_ratio, detailed_config.buffer_ending_downtrack);
490 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Route geometry size:"<<route_geometry.size());
491
492 lanelet::BasicPoint2d state_pos(state.x_pos_global, state.y_pos_global);
493 double current_downtrack = wm->routeTrackPos(state_pos).downtrack;
494 int nearest_pt_index = get_nearest_index_by_downtrack(route_geometry, wm, current_downtrack);
495 int ending_pt_index = get_nearest_index_by_downtrack(route_geometry, wm, ending_downtrack);
496 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Nearest pt index in maneuvers to points: "<< nearest_pt_index);
497 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Ending pt index in maneuvers to points: "<< ending_pt_index);
498
499 ending_state_before_buffer.x_pos_global = route_geometry[ending_pt_index].x();
500 ending_state_before_buffer.y_pos_global = route_geometry[ending_pt_index].y();
501
502 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "ending_state_before_buffer_:"<<ending_state_before_buffer.x_pos_global <<
503 ", ending_state_before_buffer_.y_pos_global" << ending_state_before_buffer.y_pos_global);
504
505
506 double route_length = wm->getRouteEndTrackPos().downtrack;
507
508 if (ending_downtrack + detailed_config.buffer_ending_downtrack < route_length)
509 {
510 ending_pt_index = get_nearest_index_by_downtrack(route_geometry, wm, ending_downtrack + detailed_config.buffer_ending_downtrack);
511 }
512 else
513 {
514 ending_pt_index = route_geometry.size() - 1;
515 }
516
517 lanelet::BasicLineString2d future_route_geometry(route_geometry.begin() + nearest_pt_index, route_geometry.begin() + ending_pt_index);
518 bool first = true;
519 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Future geom size:"<< future_route_geometry.size());
520
521 for (auto p : future_route_geometry)
522 {
523 if (first && !points_and_target_speeds.empty())
524 {
525 first = false;
526 continue; // Skip the first point if we have already added points from a previous maneuver to avoid duplicates
527 }
528 PointSpeedPair pair;
529 pair.point = p;
530 //If current speed is above min speed, keep at current speed. Otherwise use end speed from maneuver.
531 pair.speed = (state.longitudinal_vel > detailed_config.minimum_speed) ? state.longitudinal_vel : lane_change_maneuver.end_speed;
532 points_and_target_speeds.push_back(pair);
533
534 }
535 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Const speed assigned:"<<points_and_target_speeds.back().speed);
536 return points_and_target_speeds;
537
538
539 }
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 139 of file helper_functions.cpp.

141 {
142 lanelet::BasicPoint2d state_pos(state.x_pos_global, state.y_pos_global);
143 double ending_downtrack = wm->routeTrackPos(state_pos).downtrack;
144 return get_nearest_index_by_downtrack(points, wm, ending_downtrack);
145 }

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 88 of file helper_functions.cpp.

89 {
90 if(std::empty(points)){
91 RCLCPP_WARN_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Empty points vector received, returning -1");
92 return -1;
93 }
94
95 // Find first point with a downtrack greater than target_downtrack
96 const auto itr = std::find_if(std::cbegin(points), std::cend(points),
97 [&wm = std::as_const(wm), target_downtrack](const auto & point) { return wm->routeTrackPos(point).downtrack > target_downtrack; });
98
99 int best_index = std::size(points) - 1;
100
101 // Set best_index to the last point with a downtrack less than target_downtrack
102 if(itr != std::cbegin(points)){
103 best_index = std::distance(std::cbegin(points), std::prev(itr));
104 }
105 else{
106 best_index = 0;
107 }
108
109 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());
110
111 return best_index;
112 }

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 128 of file helper_functions.cpp.

130 {
131 lanelet::BasicPoint2d state_pos(state.x_pos_global, state.y_pos_global);
132 double ending_downtrack = wm->routeTrackPos(state_pos).downtrack;
133 std::vector<lanelet::BasicPoint2d> basic_points;
134 std::vector<double> speeds;
135 split_point_speed_pairs(points, &basic_points, &speeds);
136 return get_nearest_index_by_downtrack(basic_points, wm, ending_downtrack);
137 }

References get_nearest_index_by_downtrack(), and split_point_speed_pairs().

Here is the call graph for this function:

◆ get_nearest_point_index() [1/3]

size_t basic_autonomy::waypoint_generation::get_nearest_point_index ( const std::vector< carma_planning_msgs::msg::TrajectoryPlanPoint > &  trajectory,
const lanelet::BasicPoint2d &  position 
)

Find the index of the closest trajectory plan point to a given position.

This function iterates through the trajectory points and determines the one closest to the provided 2D position.

Parameters
trajectoryA vector of trajectory plan points.
positionThe reference 2D point.
Returns
The index of the trajectory point closest to the given position.

Definition at line 66 of file helper_functions.cpp.

69 {
70 size_t closest_idx = 0;
71 double min_dist = std::numeric_limits<double>::max();
72
73 for (size_t i = 0; i < trajectory.size(); i++)
74 {
75 auto dist = sqrt(pow(position.x() - trajectory.at(i).x, 2) +
76 pow(position.y() - trajectory.at(i).y, 2));
77
78 if (dist < min_dist)
79 {
80 min_dist = dist;
81 closest_idx = i;
82 }
83 }
84
85 return closest_idx;
86 }

References process_bag::i.

◆ get_nearest_point_index() [2/3]

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(), create_lanechange_geometry(), yield_plugin::YieldPlugin::plan_trajectory_callback(), and light_controlled_intersection_tactical_plugin::LightControlledIntersectionTacticalPlugin::planTrajectorySmoothing().

Here is the caller graph for this function:

◆ get_nearest_point_index() [3/3]

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 1335 of file basic_autonomy.cpp.

1336 {
1337 if (yield_plan.trajectory_points.size() < 2)
1338 {
1339 RCLCPP_WARN(node_handler->get_logger(), "Invalid Yield Trajectory with less than 2 points!");
1340 return false;
1341 }
1342
1343 RCLCPP_DEBUG_STREAM(node_handler->get_logger(), "Yield Trajectory Time" << rclcpp::Time(yield_plan.trajectory_points[0].target_time).seconds());
1344 RCLCPP_DEBUG_STREAM(node_handler->get_logger(), "Now:" << node_handler->now().seconds());
1345
1346 if (rclcpp::Time(yield_plan.trajectory_points[0].target_time) + rclcpp::Duration(5.0, 0) > node_handler->now())
1347 {
1348 return true;
1349 }
1350 else
1351 {
1352 RCLCPP_WARN_STREAM(node_handler->get_logger(), "Invalid Yield Trajectory with old target_time: " <<
1353 std::to_string(rclcpp::Time(yield_plan.trajectory_points[0].target_time).seconds()) << ", where now: " <<
1354 std::to_string(node_handler->now().seconds()));
1355 }
1356
1357 return false;
1358 }

References carma_cooperative_perception::to_string().

Referenced by modify_trajectory_to_yield_to_obstacles().

Here is the call graph for this function:
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 645 of file basic_autonomy.cpp.

646 {
647 double min = std::numeric_limits<double>::max();
648 size_t best_idx = -1;
649 for (size_t i = 0; i < values.size(); i++)
650 {
651 if (excluded.find(i) != excluded.end())
652 {
653 continue;
654 }
655
656 if (values[i] < min)
657 {
658 min = values[i];
659 best_idx = i;
660 }
661 }
662 return std::make_pair(min, best_idx);
663 }

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 1360 of file basic_autonomy.cpp.

1366 {
1367 RCLCPP_DEBUG(node_handler->get_logger(), "Object avoidance activated");
1368
1369 if (!yield_client || !yield_client->service_is_ready())
1370 {
1371 throw std::runtime_error("Yield Client is not set or unavailable after configuration state of lifecycle");
1372 }
1373
1374 RCLCPP_DEBUG(node_handler->get_logger(), "Yield Client is valid");
1375
1376 auto yield_srv = std::make_shared<carma_planning_msgs::srv::PlanTrajectory::Request>();
1377 yield_srv->initial_trajectory_plan = resp->trajectory_plan;
1378 yield_srv->vehicle_state = req->vehicle_state;
1379
1380 auto yield_resp = yield_client->async_send_request(yield_srv);
1381
1382 auto future_status = yield_resp.wait_for(std::chrono::milliseconds(yield_plugin_service_call_timeout));
1383
1384 if (future_status != std::future_status::ready)
1385 {
1386 // Sometimes the yield plugin's service call may be unsuccessful due to its computationally expensive logic.
1387 // However, consecutive calls can be successful, so return original trajectory for now
1388 RCLCPP_WARN(node_handler->get_logger(), "Service request to yield plugin timed out waiting on a reply from the service server");
1389 return resp;
1390 }
1391
1392 RCLCPP_DEBUG(node_handler->get_logger(), "Received Traj from Yield");
1393 carma_planning_msgs::msg::TrajectoryPlan yield_plan = yield_resp.get()->trajectory_plan;
1394 if (is_valid_yield_plan(node_handler, yield_plan))
1395 {
1396 RCLCPP_DEBUG(node_handler->get_logger(), "Yield trajectory validated");
1397 resp->trajectory_plan = yield_plan;
1398 }
1399 else
1400 {
1401 // This logic used to throw. However, yield_plugin is intermittently returning invalid trajectory when it shouldn't
1402 // TODO: CAR-6118 is tracking it
1403 RCLCPP_WARN_STREAM(node_handler->get_logger(), "Invalid yield trajectory detected, returning original trajectory of size: " <<
1404 resp->trajectory_plan.trajectory_points.size());
1405 }
1406
1407 return resp;
1408 }
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 665 of file basic_autonomy.cpp.

666 {
667 if (downtracks.size() != curv_speeds.size())
668 {
669 throw std::invalid_argument("Downtracks and speeds do not have the same size");
670 }
671
672 if (accel_limit <= 0)
673 {
674 throw std::invalid_argument("Accel limits should be positive");
675 }
676
677 bool optimize = true;
678 std::unordered_set<size_t> visited_idx;
679 visited_idx.reserve(curv_speeds.size());
680
681 std::vector<double> output = curv_speeds;
682
683 while (optimize)
684 {
685 auto min_pair = min_with_exclusions(curv_speeds, visited_idx);
686 int min_idx = std::get<1>(min_pair);
687 if (min_idx == -1)
688 {
689 break;
690 }
691
692 visited_idx.insert(min_idx); // Mark this point as visited
693
694 double v_i = std::get<0>(min_pair);
695 double x_i = downtracks[min_idx];
696 for (int i = min_idx - 1; i > 0; i--)
697 { // NOTE: Do not use size_t for i type here as -- with > 0 will result in overflow
698 // First point's speed is left unchanged as it is current speed of the vehicle
699 double v_f = curv_speeds[i];
700 double dv = v_f - v_i;
701
702 double x_f = downtracks[i];
703 double dx = x_f - x_i;
704
705 if (dv > 0)
706 {
707 v_f = std::min(v_f, sqrt(v_i * v_i - 2 * accel_limit * dx)); // inverting accel as we are only visiting deceleration case
708 visited_idx.insert(i);
709 }
710 else if (dv < 0)
711 {
712 break;
713 }
714 output[i] = v_f;
715 v_i = v_f;
716 x_i = x_f;
717 }
718 }
719
720 log::printDoublesPerLineWithPrefix("only_reverse[i]: ", output);
721
722 output = trajectory_utils::apply_accel_limits_by_distance(downtracks, output, accel_limit, accel_limit);
723 log::printDoublesPerLineWithPrefix("after_forward[i]: ", output);
724
725 return output;
726 }
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 visualize_xodr::dx, 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 1215 of file basic_autonomy.cpp.

1216 {
1217 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Processing latest TrajectoryPlan message");
1218
1219 std::vector<double> times;
1220 std::vector<double> downtracks;
1221
1222 std::vector<carma_planning_msgs::msg::TrajectoryPlanPoint> trajectory_points = tp.trajectory_points;
1223
1224 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Original Trajectory size:"<<trajectory_points.size());
1225
1226
1227 trajectory_utils::conversions::trajectory_to_downtrack_time(trajectory_points, &downtracks, &times);
1228
1229 //detect stopping case
1230 size_t stopping_index = 0;
1231 for (size_t i = 1; i < times.size(); i++)
1232 {
1233 if (times[i] == times[i - 1]) //if exactly same, it is stopping case
1234 {
1235 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Detected a stopping case where times is exactly equal: " << times[i-1]);
1236 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "And index of that is: " << i << ", where size is: " << times.size());
1237 stopping_index = i;
1238 break;
1239 }
1240 }
1241
1242 std::vector<double> speeds;
1243 try
1244 {
1245 trajectory_utils::conversions::time_to_speed(downtracks, times, tp.initial_longitudinal_velocity, &speeds);
1246 }
1247 catch(const std::runtime_error& error)
1248 {
1249 // This can only happen if there was negative speed in trajectory generation which usually happens when intending to stop.
1250 // The plugin is catching that error and logging it for the user to correct the origin plugin's logic, but continues
1251 // the operation by forcing the negative values to be 0, which is the intention usually.
1252 RCLCPP_WARN_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Detected a negative speed from <point,time> to <point,speed> trajectory conversion with error: "
1253 << error.what() << ". Replacing the negative speed with 0.0 speed, but please revisit the trajectory logic. "
1254 "Responsible plugin is: " << trajectory_points[std::find(speeds.begin(), speeds.end(), 0.0) - speeds.begin()].planner_plugin_name);
1255 }
1256
1257 if (speeds.size() != trajectory_points.size())
1258 {
1259 throw std::invalid_argument("Speeds and trajectory points sizes do not match");
1260 }
1261
1262 for (size_t i = 0; i < speeds.size(); i++) { // Ensure 0 is min speed
1263 if (stopping_index != 0 && i >= stopping_index - 1)
1264 {
1265 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "Made it to 0, i: " << i);
1266
1267 speeds[i] = 0.0; //stopping case
1268 }
1269 else
1270 {
1271 speeds[i] = std::max(0.0, speeds[i]);
1272 }
1273 }
1274
1275 std::vector<double> lag_speeds;
1276 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
1277
1278 autoware_auto_msgs::msg::Trajectory autoware_trajectory;
1279 autoware_trajectory.header = tp.header;
1280 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "size: " << trajectory_points.size());
1281
1282 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."
1283 //large portion of the points are not needed anyways
1284 for (int i = 0; i < max_size; i++)
1285 {
1286 autoware_auto_msgs::msg::TrajectoryPoint autoware_point;
1287
1288 autoware_point.x = trajectory_points[i].x;
1289 autoware_point.y = trajectory_points[i].y;
1290 autoware_point.longitudinal_velocity_mps = lag_speeds[i];
1291 double yaw = 0.0;
1292 if (i< max_size-1)
1293 {
1294 yaw = std::atan2(trajectory_points[i+1].y - trajectory_points[i].y, trajectory_points[i+1].x - trajectory_points[i].x);
1295
1296 }
1297 else
1298 {
1299 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);
1300 // last point in the trajectory will have yaw value of its previous point to avoid sudden steering in some conditions
1301 }
1302 autoware_point.heading.real = std::cos(yaw/2);
1303 autoware_point.heading.imag = std::sin(yaw/2);
1304
1305 autoware_point.time_from_start = rclcpp::Duration::from_nanoseconds(static_cast<int64_t>(times[i] * 1e9));
1306 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 <<
1307 ", y: " << trajectory_points[i].y <<
1308 ", speed: " << lag_speeds[i]* 2.23694 << "mph");
1309 autoware_trajectory.points.push_back(autoware_point);
1310 }
1311
1312 return autoware_trajectory;
1313 }
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, osm_transform::x, and osm_transform::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 407 of file basic_autonomy.cpp.

407 {
408
409 auto start_time = std::chrono::high_resolution_clock::now(); // Start timing the execution time for planning so it can be logged
410
411 std::vector<std::vector<lanelet::BasicPoint2d>> output;
412
413 //Fit centerlines to a spline
414 std::unique_ptr<smoothing::SplineI> fit_curve_1 = compute_fit(line_1); // Compute splines based on curve points
415 if (!fit_curve_1)
416 {
417 throw std::invalid_argument("Could not fit a spline curve along the starting_lane centerline points!");
418 }
419
420 std::unique_ptr<smoothing::SplineI> fit_curve_2 = compute_fit(line_2); // Compute splines based on curve points
421 if (!fit_curve_2)
422 {
423 throw std::invalid_argument("Could not fit a spline curve along the ending_lane centerline points!");
424 }
425
426 //Sample spline to get centerlines of equal size
427 std::vector<lanelet::BasicPoint2d> all_sampling_points_line1;
428 std::vector<lanelet::BasicPoint2d> all_sampling_points_line2;
429
430 size_t total_point_size = std::min(line_1.size(), line_2.size());
431
432 all_sampling_points_line1.reserve(1 + total_point_size * 2);
433 std::vector<double> downtracks_raw_line1 = carma_wm::geometry::compute_arc_lengths(line_1);
434 //int total_step_along_curve1 = static_cast<int>(downtracks_raw_line1.back() / 2.0);
435 //double step_threshold_line1 = (double)total_step_along_curve1 / (double)total_point_size;
436 //TODO: are we missing some computation here? step_threshold_line1 and step_threshold_line2 are not used anywhere
437 // and these calcs can be deleted (see below also).
438
439 all_sampling_points_line2.reserve(1 + total_point_size * 2);
440 std::vector<double> downtracks_raw_line2 = carma_wm::geometry::compute_arc_lengths(line_2);
441 //TODO: unused variable: int total_step_along_curve2 = static_cast<int>(downtracks_raw_line2.back() / 2.0);
442 //TODO: unused variable: double step_threshold_line2 = (double)total_step_along_curve2 / (double)total_point_size;
443
444 double scaled_steps_along_curve = 0.0; // from 0 (start) to 1 (end) for the whole trajectory
445
446
447 all_sampling_points_line2.reserve(1 + total_point_size * 2);
448
449 for(size_t i = 0;i<total_point_size; ++i){
450 lanelet::BasicPoint2d p1 = (*fit_curve_1)(scaled_steps_along_curve);
451 lanelet::BasicPoint2d p2 = (*fit_curve_2)(scaled_steps_along_curve);
452 all_sampling_points_line1.push_back(p1);
453 all_sampling_points_line2.push_back(p2);
454
455 scaled_steps_along_curve += 1.0 / total_point_size; //adding steps_along_curve_step_size
456 }
457
458 output.push_back(all_sampling_points_line1);
459 output.push_back(all_sampling_points_line2);
460
461 auto end_time = std::chrono::high_resolution_clock::now();
462
463 auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time);
464 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(BASIC_AUTONOMY_LOGGER), "ExecutionTime for resample lane change centerlines: " << duration.count() << " milliseconds");
465
466 return output;
467 }

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 114 of file helper_functions.cpp.

117 {
118 basic_points->reserve(points.size());
119 speeds->reserve(points.size());
120
121 for (const auto& p : points)
122 {
123 basic_points->push_back(p.point);
124 speeds->push_back(p.speed);
125 }
126 }

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 728 of file basic_autonomy.cpp.

731 {
732 if (points.size() != times.size() || points.size() != yaws.size())
733 {
734 throw std::invalid_argument("All input vectors must have the same size");
735 }
736
737 std::vector<carma_planning_msgs::msg::TrajectoryPlanPoint> traj;
738 traj.reserve(points.size());
739
740 for (size_t i = 0; i < points.size(); i++)
741 {
742 carma_planning_msgs::msg::TrajectoryPlanPoint tpp;
743 rclcpp::Duration relative_time = rclcpp::Duration::from_nanoseconds(static_cast<int64_t>(times[i] * 1e9)); // Conversion of times[i] from seconds to nanoseconds
744 tpp.target_time = startTime + relative_time;
745 tpp.x = points[i].x();
746 tpp.y = points[i].y();
747 tpp.yaw = yaws[i];
748
749 tpp.controller_plugin_name = desired_controller_plugin;
750 //tpp.planner_plugin_name //Planner plugin name is filled in the tactical plugin
751
752 traj.push_back(tpp);
753 }
754
755 return traj;
756 }

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().