24 std::shared_ptr<carma_ros2_utils::CarmaLifecycleNode> nh)
25 :wm_(wm), config_(config), plugin_name_(plugin_name), nh_(nh)
30 carma_planning_msgs::srv::PlanTrajectory::Request::SharedPtr req,
31 carma_planning_msgs::srv::PlanTrajectory::Response::SharedPtr resp)
33 std::chrono::system_clock::time_point start_time = std::chrono::system_clock::now();
35 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"Starting light controlled intersection trajectory planning");
37 if(req->maneuver_index_to_plan >= req->maneuver_plan.maneuvers.size())
39 throw std::invalid_argument(
40 "Light Control Intersection Plugin asked to plan invalid maneuver index: " +
std::to_string(req->maneuver_index_to_plan) +
41 " for plan of size: " +
std::to_string(req->maneuver_plan.maneuvers.size()));
44 std::vector<carma_planning_msgs::msg::Maneuver> maneuver_plan;
46 if(req->maneuver_plan.maneuvers[req->maneuver_index_to_plan].type == carma_planning_msgs::msg::Maneuver::LANE_FOLLOWING
49 maneuver_plan.push_back(req->maneuver_plan.maneuvers[req->maneuver_index_to_plan]);
50 resp->related_maneuvers.push_back(req->maneuver_index_to_plan);
54 throw std::invalid_argument(
"Light Control Intersection Plugin asked to plan unsupported maneuver");
57 lanelet::BasicPoint2d veh_pos(req->vehicle_state.x_pos_global, req->vehicle_state.y_pos_global);
58 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"Planning state x:" << req->vehicle_state.x_pos_global <<
" , y: " << req->vehicle_state.y_pos_global);
62 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"Current_downtrack: "<<
current_downtrack_);
64 auto current_lanelets =
wm_->getLaneletsFromPoint({req->vehicle_state.x_pos_global, req->vehicle_state.y_pos_global});
65 lanelet::ConstLanelet current_lanelet;
67 if (current_lanelets.empty())
69 RCLCPP_ERROR_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"Given vehicle position is not on the road! Returning...");
74 auto llt_on_route_optional =
wm_->getFirstLaneletOnShortestPath(current_lanelets);
76 if (llt_on_route_optional){
77 current_lanelet = llt_on_route_optional.value();
80 RCLCPP_WARN_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"When identifying the corresponding lanelet for requested trajectory plan's state, x: "
81 << req->vehicle_state.x_pos_global <<
", y: " << req->vehicle_state.y_pos_global <<
", no possible lanelet was found to be on the shortest path."
82 <<
"Picking arbitrary lanelet: " << current_lanelets[0].id() <<
", instead");
83 current_lanelet = current_lanelets[0];
86 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"Current_lanelet: " << current_lanelet.id());
90 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"speed_limit_: " <<
speed_limit_);
109 bool is_new_case_successful =
GET_MANEUVER_PROPERTY(maneuver_plan.front(), parameters.int_valued_meta_data[1]);
114 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"all variables are set!");
115 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"is_last_case_successful_.get(): " << (
int)
is_last_case_successful_.get());
122 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"Not all variables are set...");
127 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"traj points size: " <<
last_trajectory_.trajectory_points.size() <<
", last_final_speeds_ size: " <<
130 size_t idx_to_start_new_traj = 0;
137 idx_to_start_new_traj =
i;
147 && is_new_case_successful ==
true
149 && rclcpp::Time(
last_trajectory_.trajectory_points.back().target_time) > rclcpp::Time(req->header.stamp) + rclcpp::Duration(1 * 1e9))
152 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"Last TRAJ's target time: " <<
std::to_string(rclcpp::Time(
last_trajectory_.trajectory_points.back().target_time).seconds()) <<
", and stamp:" <<
std::to_string(rclcpp::Time(req->header.stamp).seconds()));
153 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"USING LAST TRAJ: " << (
int)
last_case_.get());
157 && is_new_case_successful ==
false
161 && rclcpp::Time(
last_trajectory_.trajectory_points.back().target_time).seconds() > rclcpp::Time(req->header.stamp).seconds())
165 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"EDGE CASE: USING LAST TRAJ: " << (
int)
last_case_.get());
168 if (!resp->trajectory_plan.trajectory_points.empty())
170 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"Debug: new case:" << (
int) new_case <<
", is_new_case_successful: " << is_new_case_successful);
174 resp->maneuver_status.push_back(carma_planning_msgs::srv::PlanTrajectory::Response::MANEUVER_IN_PROGRESS);
176 std::chrono::system_clock::time_point end_time = std::chrono::system_clock::now();
178 auto duration = end_time - start_time;
179 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"ExecutionTime Using New: " << std::chrono::duration<double>(duration).count());
193 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"points_and_target_speeds: " << points_and_target_speeds.size());
195 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"PlanTrajectory");
198 carma_planning_msgs::msg::TrajectoryPlan trajectory;
199 trajectory.header.frame_id =
"map";
200 trajectory.header.stamp = req->header.stamp;
209 for (
auto& p : trajectory.trajectory_points) {
213 if (trajectory.trajectory_points.size () < 2)
216 && rclcpp::Time(
last_trajectory_.trajectory_points.back().target_time) > rclcpp::Time(req->header.stamp))
219 RCLCPP_WARN_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"Failed to generate new trajectory, so using last valid trajectory!");
223 resp->trajectory_plan = trajectory;
224 RCLCPP_WARN_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"Failed to generate new trajectory or use old valid trajectory, so returning empty/invalid trajectory!");
230 resp->trajectory_plan = trajectory;
234 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"USING NEW: Target time: " <<
std::to_string(rclcpp::Time(
last_trajectory_.trajectory_points.back().target_time).seconds()) <<
", and stamp:" <<
std::to_string(rclcpp::Time(req->header.stamp).seconds()));
235 if (is_new_case_successful)
241 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"USING NEW CASE!!! : " << (
int)
last_case_.get());
244 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"Debug: new case:" << (
int) new_case <<
", is_new_case_successful: " << is_new_case_successful);
256 RCLCPP_DEBUG(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"Ignored Object Avoidance");
259 resp->maneuver_status.push_back(carma_planning_msgs::srv::PlanTrajectory::Response::MANEUVER_IN_PROGRESS);
261 std::chrono::system_clock::time_point end_time = std::chrono::system_clock::now();
263 auto duration = end_time - start_time;
264 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"ExecutionTime Using Last: " << std::chrono::duration<double>(duration).count());
272 if (points_and_target_speeds.empty())
274 throw std::invalid_argument(
"Point and target speed list is empty! Unable to apply case one speed profile...");
278 double planning_downtrack_start = wm->routeTrackPos(points_and_target_speeds[0].
point).downtrack;
281 double total_distance_needed = remaining_dist;
282 double dist1 = tsp.
x1_ - start_dist;
283 double dist2 = tsp.
x2_ - start_dist;
284 double dist3 = tsp.
x3_ - start_dist;
286 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"total_distance_needed: " << total_distance_needed <<
"\n" <<
287 "dist1: " << dist1 <<
"\n" <<
288 "dist2: " << dist2 <<
"\n" <<
290 double algo_min_speed = std::min({tsp.
v1_,tsp.
v2_,tsp.
v3_});
291 double algo_max_speed = std::max({tsp.
v1_,tsp.
v2_,tsp.
v3_});
293 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"found algo_minimum_speed: " << algo_min_speed <<
"\n" <<
294 "algo_max_speed: " << algo_max_speed);
296 double total_dist_planned = 0;
298 if (planning_downtrack_start < start_dist)
302 total_dist_planned = planning_downtrack_start - start_dist;
303 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"buffered section is present. Adjusted total_dist_planned to: " << total_dist_planned);
306 double prev_speed = starting_speed;
307 auto prev_point = points_and_target_speeds.front();
309 for(
auto& p : points_and_target_speeds)
311 double delta_d = lanelet::geometry::distance2d(prev_point.point, p.point);
312 total_dist_planned += delta_d;
320 speed_i = starting_speed;
322 else if(total_dist_planned <= dist1 +
epsilon_){
324 speed_i = sqrt(pow(starting_speed, 2) + 2 * tsp.
a1_ * total_dist_planned);
326 else if(total_dist_planned > dist1 && total_dist_planned <= dist2 +
epsilon_){
328 speed_i = sqrt(std::max(pow(tsp.
v1_, 2) + 2 * tsp.
a2_ * (total_dist_planned - dist1), 0.0));
330 else if (total_dist_planned > dist2 && total_dist_planned <= dist3 +
epsilon_)
333 speed_i = sqrt(std::max(pow(tsp.
v2_, 2) + 2 * tsp.
a3_ * (total_dist_planned - dist2), 0.0));
338 speed_i = prev_speed;
344 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"Detected nan number from equations. Set to " << speed_i);
348 p.speed = std::min({p.speed,
speed_limit_, algo_max_speed});
349 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"Applied speed: " << p.speed <<
", at dist: " << total_dist_planned);
352 prev_speed = p.speed;
360 throw std::invalid_argument(
"There must be 9 float_valued_meta_data and 2 int_valued_meta_data to apply algorithm's parameters.");
381 double entry_dist = ending_downtrack - starting_downtrack;
385 departure_speed, tsp);
390 lanelet::Optional<carma_wm::TrafficRulesConstPtr> traffic_rules = wm->getTrafficRules();
393 return (*traffic_rules)->speedLimit(llt).speedLimit.value();
397 throw std::invalid_argument(
"Valid traffic rules object could not be built");
402 carma_planning_msgs::msg::VehicleState &ending_state_before_buffer,
const carma_planning_msgs::msg::VehicleState& state,
405 std::vector<PointSpeedPair> points_and_target_speeds;
408 std::unordered_set<lanelet::Id> visited_lanelets;
409 std::vector<carma_planning_msgs::msg::Maneuver> processed_maneuvers;
410 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"VehDowntrack: "<<max_starting_downtrack);
413 if(maneuvers.size() == 1)
415 auto maneuver = maneuvers.front();
419 starting_downtrack = std::min(starting_downtrack, max_starting_downtrack);
421 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"Used downtrack: " << starting_downtrack);
426 throw std::invalid_argument(
"No time_to_schedule_entry is provided in float_valued_meta_data");
429 RCLCPP_DEBUG_STREAM(rclcpp::get_logger(
"light_controlled_intersection_tactical_plugin"),
"Creating Lane Follow Geometry");
431 points_and_target_speeds.insert(points_and_target_speeds.end(), lane_follow_points.begin(), lane_follow_points.end());
432 processed_maneuvers.push_back(maneuver);
436 throw std::invalid_argument(
"Light Control Intersection Plugin can only create a geometry profile for one maneuver");
440 if(!processed_maneuvers.empty() && processed_maneuvers.back().type == carma_planning_msgs::msg::Maneuver::LANE_FOLLOWING){
441 points_and_target_speeds =
add_lanefollow_buffer(wm, points_and_target_speeds, processed_maneuvers, ending_state_before_buffer, detailed_config);
444 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::VehicleState ending_state_before_buffer_
carma_ros2_utils::ClientPtr< carma_planning_msgs::srv::PlanTrajectory > yield_client_
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_
double last_successful_scheduled_entry_time_
double current_downtrack_
std::vector< double > last_final_speeds_
boost::optional< bool > is_last_case_successful_
carma_planning_msgs::msg::TrajectoryPlan last_trajectory_
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 setConfig(const Config &config)
Setter function to set a new config for this object.
double findSpeedLimit(const lanelet::ConstLanelet &llt, const carma_wm::WorldModelConstPtr &wm) const
Given a Lanelet, find it's associated Speed Limit.
std::shared_ptr< carma_ros2_utils::CarmaLifecycleNode > nh_
void set_yield_client(carma_ros2_utils::ClientPtr< carma_planning_msgs::srv::PlanTrajectory > client)
set the yield service
carma_wm::WorldModelConstPtr wm_
LightControlledIntersectionTacticalPlugin(carma_wm::WorldModelConstPtr wm, const Config &config, const std::string &plugin_name, std::shared_ptr< carma_ros2_utils::CarmaLifecycleNode > nh)
LightControlledIntersectionTacticalPlugin constructor.
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)
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.
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")
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...
auto to_string(const UtmZone &zone) -> std::string
std::shared_ptr< const WorldModel > WorldModelConstPtr
Stuct containing the algorithm configuration values for light_controlled_intersection_tactical_plugin...
int curvature_moving_average_window_size
int turn_downsample_ratio
double lateral_accel_limit
double buffer_ending_downtrack
double curve_resample_step_size
double algorithm_evaluation_period
bool enable_object_avoidance
int default_downsample_ratio
double trajectory_time_length
double algorithm_evaluation_distance
int speed_moving_average_window_size
double vehicle_accel_limit
int tactical_plugin_service_call_timeout