28 const std::string& plugin_name,
29 std::shared_ptr<carma_ros2_utils::CarmaLifecycleNode> nh)
30 :wm_(wm), config_(config), nh_(nh), plugin_name_(plugin_name),
31 debug_publisher_(debug_publisher)
37 const rclcpp::Time& current_time,
38 double min_remaining_time_seconds)
const
50 if (rclcpp::Duration min_time_remaining =
51 rclcpp::Duration::from_seconds(min_remaining_time_seconds);
52 last_point_time <= current_time + min_time_remaining)
73 TSCase new_case,
bool is_new_case_successful,
const rclcpp::Time& current_time)
84 if (
last_case_.get() == new_case && is_new_case_successful ==
true)
93 is_new_case_successful ==
false &&
109 const std::vector<carma_planning_msgs::msg::Maneuver>& maneuver_plan,
110 const carma_planning_msgs::srv::PlanTrajectory::Request::SharedPtr& req,
111 std::vector<double>& final_speeds)
117 "intersection_transit",
135 wpg_general_config, wpg_detail_config);
139 points_and_target_speeds);
142 carma_planning_msgs::msg::TrajectoryPlan new_trajectory;
143 new_trajectory.header.frame_id =
"map";
144 new_trajectory.header.stamp = req->header.stamp;
148 new_trajectory.trajectory_points =
150 points_and_target_speeds,
157 return new_trajectory;
165 "all variables are set!");
177 "Not all variables are set...");
186 carma_planning_msgs::srv::PlanTrajectory::Request::SharedPtr req,
187 carma_planning_msgs::srv::PlanTrajectory::Response::SharedPtr resp)
190 if(req->maneuver_index_to_plan >= req->maneuver_plan.maneuvers.size())
192 throw std::invalid_argument(
193 "Light Control Intersection Tactical Plugin was asked to plan invalid "
195 +
" for plan of size: " +
std::to_string(req->maneuver_plan.maneuvers.size()));
199 std::vector<carma_planning_msgs::msg::Maneuver> maneuver_plan;
200 if(req->maneuver_plan.maneuvers[req->maneuver_index_to_plan].type ==
201 carma_planning_msgs::msg::Maneuver::LANE_FOLLOWING
205 maneuver_plan.push_back(req->maneuver_plan.maneuvers[req->maneuver_index_to_plan]);
206 resp->related_maneuvers.push_back(req->maneuver_index_to_plan);
210 throw std::invalid_argument(
"Light Control Intersection Tactical Plugin "
211 "was asked to plan unsupported maneuver");
215 lanelet::BasicPoint2d veh_pos(req->vehicle_state.x_pos_global,
216 req->vehicle_state.y_pos_global);
218 "Planning state x:" << req->vehicle_state.x_pos_global
219 <<
" , y: " << req->vehicle_state.y_pos_global);
226 auto current_lanelets =
wm_->getLaneletsFromPoint({req->vehicle_state.x_pos_global,
227 req->vehicle_state.y_pos_global});
230 << current_lanelets.size());
232 lanelet::ConstLanelet current_lanelet;
234 if (current_lanelets.empty())
237 "Given vehicle position is not on the road! Returning...");
242 if (
auto llt_on_route_optional =
wm_->getFirstLaneletOnShortestPath(current_lanelets);
243 llt_on_route_optional)
245 current_lanelet = llt_on_route_optional.value();
250 "When identifying the corresponding lanelet for requested trajectory plan's state, "
251 <<
"x: " << req->vehicle_state.x_pos_global
252 <<
", y: " << req->vehicle_state.y_pos_global
253 <<
", no possible lanelet was found to be on the shortest path."
254 <<
"Picking arbitrary lanelet: " << current_lanelets[0].id() <<
", instead");
256 current_lanelet = current_lanelets[0];
260 "Current_lanelet: " << current_lanelet.id());
267 bool is_new_case_successful =
272 maneuver_plan.front(), parameters.int_valued_meta_data[0]);
278 size_t idx_to_start_new_traj =
289 std::vector<carma_planning_msgs::msg::TrajectoryPlanPoint>
295 auto current_time = rclcpp::Time(req->header.stamp);
298 auto last_trajectory_time_bound =
304 resp->trajectory_plan.trajectory_points = last_trajectory_time_bound;
307 "USING LAST TRAJ WITH CASE: " << (
int)
last_case_.get());
312 for (
auto& p : resp->trajectory_plan.trajectory_points) {
316 debug_msg_.trajectory_plan = resp->trajectory_plan;
323 std::vector<double> new_final_speeds;
324 if (carma_planning_msgs::msg::TrajectoryPlan new_trajectory =
326 new_trajectory.trajectory_points.size() >= 2)
329 auto new_trajectory_time_bound =
333 resp->trajectory_plan = new_trajectory;
334 resp->trajectory_plan.trajectory_points = new_trajectory_time_bound;
341 "USING NEW TRAJECTORY for case: " << (
int)new_case);
348 resp->trajectory_plan.trajectory_points = last_trajectory_time_bound;
351 "Failed to generate a new trajectory, so using last valid trajectory!");
356 resp->trajectory_plan = new_trajectory;
358 "Failed to generate a new trajectory or use old valid trajectory, "
359 "so returning empty/invalid trajectory!");
368 if (is_new_case_successful) {
380 ", last_successful_scheduled_entry_time_: " <<
385 "Debug: new case:" << (
int) new_case <<
", is_new_case_successful: "
386 << is_new_case_successful);
388 resp->maneuver_status.push_back(
389 carma_planning_msgs::srv::PlanTrajectory::Response::MANEUVER_IN_PROGRESS);
393 for (
auto& p : resp->trajectory_plan.trajectory_points) {
397 debug_msg_.trajectory_plan = resp->trajectory_plan;
403 carma_planning_msgs::srv::PlanTrajectory::Request::SharedPtr req,
404 carma_planning_msgs::srv::PlanTrajectory::Response::SharedPtr resp)
406 std::chrono::system_clock::time_point start_time = std::chrono::system_clock::now();
411 "Starting light controlled intersection trajectory planning");
415 std::chrono::system_clock::time_point end_time = std::chrono::system_clock::now();
416 auto duration = end_time - start_time;
419 "ExecutionTime: " << std::chrono::duration<double>(duration).count());
425 if (points_and_target_speeds.empty())
427 throw std::invalid_argument(
"Point and target speed list is empty! Unable to apply case one speed profile...");
431 double planning_downtrack_start = wm->routeTrackPos(points_and_target_speeds[0].
point).downtrack;
434 double total_distance_needed = remaining_dist;
435 double dist1 = tsp.
x1_ - start_dist;
436 double dist2 = tsp.
x2_ - start_dist;
437 double dist3 = tsp.
x3_ - start_dist;
440 "dist1: " << dist1 <<
"\n" <<
441 "dist2: " << dist2 <<
"\n" <<
443 double algo_min_speed = std::min({tsp.
v1_,tsp.
v2_,tsp.
v3_});
444 double algo_max_speed = std::max({tsp.
v1_,tsp.
v2_,tsp.
v3_});
447 "algo_max_speed: " << algo_max_speed);
449 double total_dist_planned = 0;
451 if (planning_downtrack_start < start_dist)
455 total_dist_planned = planning_downtrack_start - start_dist;
459 double prev_speed = starting_speed;
460 auto prev_point = points_and_target_speeds.front();
462 for(
auto& p : points_and_target_speeds)
464 double delta_d = lanelet::geometry::distance2d(prev_point.point, p.point);
465 total_dist_planned += delta_d;
473 speed_i = starting_speed;
475 else if(total_dist_planned <= dist1 +
epsilon_){
477 speed_i = sqrt(pow(starting_speed, 2) + 2 * tsp.
a1_ * total_dist_planned);
479 else if(total_dist_planned > dist1 && total_dist_planned <= dist2 +
epsilon_){
481 speed_i = sqrt(std::max(pow(tsp.
v1_, 2) + 2 * tsp.
a2_ * (total_dist_planned - dist1), 0.0));
483 else if (total_dist_planned > dist2 && total_dist_planned <= dist3 +
epsilon_)
486 speed_i = sqrt(std::max(pow(tsp.
v2_, 2) + 2 * tsp.
a3_ * (total_dist_planned - dist2), 0.0));
491 speed_i = prev_speed;
501 p.speed = std::min({p.speed,
speed_limit_, algo_max_speed});
505 prev_speed = p.speed;
513 throw std::invalid_argument(
"There must be 9 float_valued_meta_data and 2 int_valued_meta_data to apply algorithm's parameters.");
534 double entry_dist = ending_downtrack - starting_downtrack;
538 entry_dist, starting_speed, departure_speed, tsp);
543 lanelet::Optional<carma_wm::TrafficRulesConstPtr> traffic_rules = wm->getTrafficRules();
546 return (*traffic_rules)->speedLimit(llt).speedLimit.value();
550 throw std::invalid_argument(
"Valid traffic rules object could not be built");
555 carma_planning_msgs::msg::VehicleState &ending_state_before_buffer,
const carma_planning_msgs::msg::VehicleState& state,
558 std::vector<PointSpeedPair> points_and_target_speeds;
561 std::unordered_set<lanelet::Id> visited_lanelets;
562 std::vector<carma_planning_msgs::msg::Maneuver> processed_maneuvers;
566 if(maneuvers.size() == 1)
568 auto maneuver = maneuvers.front();
572 starting_downtrack = std::min(starting_downtrack, max_starting_downtrack);
579 throw std::invalid_argument(
"No time_to_schedule_entry is provided in float_valued_meta_data");
584 points_and_target_speeds.insert(points_and_target_speeds.end(), lane_follow_points.begin(), lane_follow_points.end());
585 processed_maneuvers.push_back(maneuver);
589 throw std::invalid_argument(
"Light Control Intersection Tactical Plugin currently can"
590 " only create a geometry profile for one maneuver");
594 if(!processed_maneuvers.empty() && processed_maneuvers.back().type == carma_planning_msgs::msg::Maneuver::LANE_FOLLOWING){
595 points_and_target_speeds =
add_lanefollow_buffer(wm, points_and_target_speeds, processed_maneuvers, ending_state_before_buffer, detailed_config);
598 return points_and_target_speeds;
#define GET_MANEUVER_PROPERTY(mvr, property)
Macro definition to enable easier access to fields shared across the maneuver types.
carma_planning_msgs::msg::TrajectoryPlan last_trajectory_time_unbound_
carma_planning_msgs::msg::VehicleState ending_state_before_buffer_
void planTrajectoryCB(carma_planning_msgs::srv::PlanTrajectory::Request::SharedPtr req, carma_planning_msgs::srv::PlanTrajectory::Response::SharedPtr resp)
Function to process the light controlled intersection tactical plugin service call for trajectory pla...
carma_debug_ros2_msgs::msg::TrajectoryCurvatureSpeeds debug_msg_
void applyTrajectorySmoothingAlgorithm(const carma_wm::WorldModelConstPtr &wm, std::vector< PointSpeedPair > &points_and_target_speeds, double start_dist, double remaining_dist, double starting_speed, double departure_speed, TrajectoryParams tsp)
Creates a speed profile according to case one or two of the light controlled intersection,...
std::string light_controlled_intersection_strategy_
rclcpp::Time latest_traj_request_header_stamp_
double last_successful_scheduled_entry_time_
double current_downtrack_
boost::optional< bool > is_last_case_successful_
std::vector< double > last_speeds_time_unbound_
DebugPublisher debug_publisher_
bool isLastTrajectoryValid(const rclcpp::Time ¤t_time, double min_remaining_time_seconds=0.0) const
Checks if the last trajectory plan remains valid based on the current time.
void applyOptimizedTargetSpeedProfile(const carma_planning_msgs::msg::Maneuver &maneuver, const double starting_speed, std::vector< PointSpeedPair > &points_and_target_speeds)
Apply optimized target speeds to the trajectory determined for fixed-time and actuated signals....
void planTrajectorySmoothing(carma_planning_msgs::srv::PlanTrajectory::Request::SharedPtr req, carma_planning_msgs::srv::PlanTrajectory::Response::SharedPtr resp)
Smooths the trajectory as part of the trajectory planning process.
carma_planning_msgs::msg::TrajectoryPlan generateNewTrajectory(const std::vector< carma_planning_msgs::msg::Maneuver > &maneuver_plan, const carma_planning_msgs::srv::PlanTrajectory::Request::SharedPtr &req, std::vector< double > &final_speeds)
Generates a new trajectory plan based on the provided maneuver plan and request. NOTE: This function ...
void setConfig(const Config &config)
Setter function to set a new config for this object.
void logDebugInfoAboutPreviousTrajectory()
Logs debug information about the previously planned trajectory.
LightControlledIntersectionTacticalPlugin(carma_wm::WorldModelConstPtr wm, const Config &config, const DebugPublisher &debug_publisher, const std::string &plugin_name, std::shared_ptr< carma_ros2_utils::CarmaLifecycleNode > nh)
LightControlledIntersectionTacticalPlugin constructor.
const std::string LCI_TACTICAL_LOGGER
double findSpeedLimit(const lanelet::ConstLanelet &llt, const carma_wm::WorldModelConstPtr &wm) const
Given a Lanelet, find its associated Speed Limit.
std::shared_ptr< carma_ros2_utils::CarmaLifecycleNode > nh_
bool shouldUseLastTrajectory(TSCase new_case, bool is_new_case_successful, const rclcpp::Time ¤t_time)
Determines whether the last trajectory should be reused based on the planning case....
carma_wm::WorldModelConstPtr wm_
boost::optional< TSCase > last_case_
double last_successful_ending_downtrack_
std::vector< PointSpeedPair > createGeometryProfile(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 INTERSECTION_TRANSIT maneuver types ...
GeneralTrajConfig compose_general_trajectory_config(const std::string &trajectory_type, int default_downsample_ratio, int turn_downsample_ratio)
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")
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< 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< 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 t...
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.
void set_logger(rclcpp::Logger logger)
Replace the module-level logger used by all basic_autonomy functions.
rclcpp::Logger get_logger()
Return the module-level logger used by all basic_autonomy functions.
auto to_string(const UtmZone &zone) -> std::string
std::shared_ptr< const WorldModel > WorldModelConstPtr
std::function< void(const carma_debug_ros2_msgs::msg::TrajectoryCurvatureSpeeds &)> DebugPublisher
Stuct containing the algorithm configuration values for light_controlled_intersection_tactical_plugin...
int curvature_moving_average_window_size
double period_before_intersection_to_force_last_traj
int turn_downsample_ratio
double lateral_accel_limit
double buffer_ending_downtrack
double curve_resample_step_size
int default_downsample_ratio
double trajectory_time_length
double dist_before_intersection_to_force_last_traj
int speed_moving_average_window_size
double vehicle_accel_limit
double vehicle_response_lag