Carma-platform v4.2.0
CARMA Platform is built on robot operating system (ROS) and utilizes open source software (OSS) that enables Cooperative Driving Automation (CDA) features to allow Automated Driving Systems to interact and cooperate with infrastructure and other vehicles through communication.
lci_strategic_plugin.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2023 LEIDOS.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
14 * the License.
15 */
18
19#define EPSILON 0.01
20
21#define GET_MANEUVER_PROPERTY(mvr, property) \
22 (((mvr).type == carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_LEFT_TURN ? \
23 (mvr).intersection_transit_left_turn_maneuver.property : \
24 ((mvr).type == carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_RIGHT_TURN ? \
25 (mvr).intersection_transit_right_turn_maneuver.property : \
26 ((mvr).type == carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_STRAIGHT ? \
27 (mvr).intersection_transit_straight_maneuver.property : \
28 ((mvr).type == carma_planning_msgs::msg::Maneuver::LANE_CHANGE ? (mvr).lane_change_maneuver.property : \
29 (mvr).type == carma_planning_msgs::msg::Maneuver::LANE_FOLLOWING ? (mvr).lane_following_maneuver.property : \
30 throw new std::invalid_argument("GET_MANEUVER_" \
31 "PROPERTY " \
32 "(property) " \
33 "called on " \
34 "maneuver with " \
35 "invalid type " \
36 "id"))))))
37
39{
40 namespace std_ph = std::placeholders;
41
42LCIStrategicPlugin::LCIStrategicPlugin(const rclcpp::NodeOptions &options)
43 : carma_guidance_plugins::StrategicPlugin(options), tf2_buffer_(std::make_shared<tf2_ros::Buffer>(this->get_clock()))
44{
46
47 config_.vehicle_accel_limit = declare_parameter<double>("vehicle_acceleration_limit", config_.vehicle_accel_limit);
48 config_.vehicle_decel_limit = declare_parameter<double>("vehicle_deceleration_limit", config_.vehicle_decel_limit);
49 config_.vehicle_decel_limit_multiplier = declare_parameter<double>("vehicle_decel_limit_multiplier", config_.vehicle_decel_limit_multiplier);
50 config_.vehicle_accel_limit_multiplier = declare_parameter<double>("vehicle_accel_limit_multiplier", config_.vehicle_accel_limit_multiplier);
51 config_.min_approach_distance = declare_parameter<double>("min_approach_distance", config_.min_approach_distance);
52 config_.trajectory_smoothing_activation_distance = declare_parameter<double>("trajectory_smoothing_activation_distance", config_.trajectory_smoothing_activation_distance);
53 config_.stopping_location_buffer = declare_parameter<double>("stopping_location_buffer", config_.stopping_location_buffer);
54 config_.green_light_time_buffer = declare_parameter<double>("green_light_time_buffer", config_.green_light_time_buffer);
55 config_.algo_minimum_speed = declare_parameter<double>("algo_minimum_speed", config_.algo_minimum_speed);
56 config_.deceleration_fraction = declare_parameter<double>("deceleration_fraction", config_.deceleration_fraction);
57 config_.desired_distance_to_stop_buffer = declare_parameter<double>("desired_distance_to_stop_buffer", config_.desired_distance_to_stop_buffer);
58 config_.min_maneuver_planning_period = declare_parameter<double>("min_maneuver_planning_period", config_.min_maneuver_planning_period);
59 config_.strategic_plugin_name = declare_parameter<std::string>("strategic_plugin_name", config_.strategic_plugin_name);
60 config_.lane_following_plugin_name = declare_parameter<std::string>("lane_following_plugin_name", config_.lane_following_plugin_name);
61 config_.stop_and_wait_plugin_name = declare_parameter<std::string>("stop_and_wait_plugin_name", config_.stop_and_wait_plugin_name);
62 config_.intersection_transit_plugin_name = declare_parameter<std::string>("intersection_transit_plugin_name", config_.intersection_transit_plugin_name);
63 config_.enable_carma_streets_connection = declare_parameter<bool>("enable_carma_streets_connection",config_.enable_carma_streets_connection);
64 config_.mobility_rate = declare_parameter<double>("mobility_rate", config_.mobility_rate);
66 declare_parameter<long>("enable_carma_wm_spat_processing",
68 config_.vehicle_id = declare_parameter<std::string>("vehicle_id", config_.vehicle_id);
69
74};
75
76carma_ros2_utils::CallbackReturn LCIStrategicPlugin::on_configure_plugin()
77{
78 // reset config
80
81 // clang-format off
82 get_parameter<double>("vehicle_acceleration_limit", config_.vehicle_accel_limit);
83 get_parameter<double>("vehicle_deceleration_limit", config_.vehicle_decel_limit);
84 get_parameter<double>("vehicle_decel_limit_multiplier", config_.vehicle_decel_limit_multiplier);
85 get_parameter<double>("vehicle_accel_limit_multiplier", config_.vehicle_accel_limit_multiplier);
86 get_parameter<double>("min_approach_distance", config_.min_approach_distance);
87 get_parameter<double>("trajectory_smoothing_activation_distance", config_.trajectory_smoothing_activation_distance);
88 get_parameter<double>("stopping_location_buffer", config_.stopping_location_buffer);
89 get_parameter<double>("green_light_time_buffer", config_.green_light_time_buffer);
90 get_parameter<double>("algo_minimum_speed", config_.algo_minimum_speed);
91 get_parameter<double>("deceleration_fraction", config_.deceleration_fraction);
92 get_parameter<double>("desired_distance_to_stop_buffer", config_.desired_distance_to_stop_buffer);
93 get_parameter<double>("min_maneuver_planning_period", config_.min_maneuver_planning_period);
94 get_parameter<std::string>("strategic_plugin_name", config_.strategic_plugin_name);
95 get_parameter<std::string>("lane_following_plugin_name", config_.lane_following_plugin_name);
96 get_parameter<std::string>("stop_and_wait_plugin_name", config_.stop_and_wait_plugin_name);
97 get_parameter<std::string>("intersection_transit_plugin_name", config_.intersection_transit_plugin_name);
98 get_parameter<bool>("enable_carma_streets_connection", config_.enable_carma_streets_connection);
99 get_parameter<int>("enable_carma_wm_spat_processing", config_.enable_carma_wm_spat_processing);
100 get_parameter<double>("mobility_rate", config_.mobility_rate);
101 get_parameter<std::string>("vehicle_id", config_.vehicle_id);
102
107
108 // clang-format on
109
110 // Register runtime parameter update callback
111 add_on_set_parameters_callback(std::bind(&LCIStrategicPlugin::parameter_update_callback, this, std_ph::_1));
112
113 RCLCPP_INFO_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Done loading parameters: " << config_);
114
116
117 // Mobility Operation Subscriber
118 mob_operation_sub_ = create_subscription<carma_v2x_msgs::msg::MobilityOperation>("incoming_mobility_operation", 1,
119 std::bind(&LCIStrategicPlugin::mobilityOperationCb,this,std_ph::_1));
120
121 // BSM subscriber
122 bsm_sub_ = create_subscription<carma_v2x_msgs::msg::BSM>("bsm_outbound", 1,
123 std::bind(&LCIStrategicPlugin::BSMCb,this,std_ph::_1));
124
125 // set world model point from wm listener
127
128 // Activate SPAT processor, which is turned off by default,
129 // with OFF (0), ON (1)
130 get_world_model_listener()->setWMSpatProcessingState(
132
133 // Setup publishers
134 mobility_operation_pub_ = create_publisher<carma_v2x_msgs::msg::MobilityOperation>("outgoing_mobility_operation", 1);
135 case_pub_ = create_publisher<std_msgs::msg::Int8>("lci_strategic_plugin/ts_case_num", 1);
136 tf_distance_pub_ = create_publisher<std_msgs::msg::Float64>("lci_strategic_plugin/distance_remaining_to_tf", 1);
137 earliest_et_pub_ = create_publisher<std_msgs::msg::Float64>("lci_strategic_plugin/earliest_entry_time", 1);
138 et_pub_ = create_publisher<std_msgs::msg::Float64>("lci_strategic_plugin/scheduled_entry_time", 1);
139
140 // Return success if everything initialized successfully
141 return CallbackReturn::SUCCESS;
142}
143
144rcl_interfaces::msg::SetParametersResult LCIStrategicPlugin::parameter_update_callback(const std::vector<rclcpp::Parameter> &parameters)
145{
146 auto error_double = update_params<double>({
147 {"vehicle_acceleration_limit", config_.vehicle_accel_limit},
148 {"vehicle_deceleration_limit", config_.vehicle_decel_limit},
149 {"vehicle_decel_limit_multiplier", config_.vehicle_decel_limit_multiplier},
150 {"vehicle_accel_limit_multiplier", config_.vehicle_accel_limit_multiplier},
151 {"min_approach_distance", config_.min_approach_distance},
152 {"trajectory_smoothing_activation_distance", config_.trajectory_smoothing_activation_distance},
153 {"stopping_location_buffer", config_.stopping_location_buffer},
154 {"green_light_time_buffer", config_.green_light_time_buffer},
155 {"algo_minimum_speed", config_.algo_minimum_speed},
156 {"deceleration_fraction", config_.deceleration_fraction},
157 {"desired_distance_to_stop_buffer", config_.desired_distance_to_stop_buffer},
158 {"min_maneuver_planning_period", config_.min_maneuver_planning_period},
159 {"mobility_rate", config_.mobility_rate},
160 }, parameters);
161
162 rcl_interfaces::msg::SetParametersResult result;
163
164 result.successful = !error_double;
165
166 return result;
167}
168
170{
171 std_msgs::msg::Int8 case_num_msg;
172 std_msgs::msg::Float64 tf_distance;
173 std_msgs::msg::Float64 earliest_et;
174 std_msgs::msg::Float64 scheduled_et;
175
176 case_num_msg.data = static_cast<int>(last_case_num_);
177 tf_distance.data = distance_remaining_to_tf_;
178 earliest_et.data = earliest_entry_time_;
179 scheduled_et.data = scheduled_entry_time_;
180
181 case_pub_->publish(case_num_msg);
182 tf_distance_pub_->publish(tf_distance);
183 earliest_et_pub_->publish(earliest_et);
184 et_pub_->publish(scheduled_et);
185}
186
187carma_ros2_utils::CallbackReturn LCIStrategicPlugin::on_activate_plugin()
188{
189 mob_op_pub_timer_ = create_timer(get_clock(),
190 std::chrono::duration<double>(1/config_.mobility_rate),
192
193 ts_info_pub_timer_ = create_timer(get_clock(),
194 std::chrono::duration<double>(0.5),
196
197 return CallbackReturn::SUCCESS;
198}
199
200bool LCIStrategicPlugin::supportedLightState(lanelet::CarmaTrafficSignalState state) const
201{
202 switch (state)
203 {
204 // NOTE: Following cases are intentional fall through.
205 // Supported light states
206 case lanelet::CarmaTrafficSignalState::STOP_AND_REMAIN: // Solid Red
207 case lanelet::CarmaTrafficSignalState::PROTECTED_CLEARANCE: // Yellow Solid no chance of conflicting traffic
208 case lanelet::CarmaTrafficSignalState::PERMISSIVE_MOVEMENT_ALLOWED: // Solid Green there could be conflict traffic
209 case lanelet::CarmaTrafficSignalState::PROTECTED_MOVEMENT_ALLOWED: // Solid Green no chance of conflict traffic
210 // (normally used with arrows)
211 return true;
212
213 // Unsupported light states
214 case lanelet::CarmaTrafficSignalState::PERMISSIVE_CLEARANCE: // Yellow Solid there is a chance of conflicting
215 // traffic
216 case lanelet::CarmaTrafficSignalState::UNAVAILABLE: // No data available
217 case lanelet::CarmaTrafficSignalState::DARK: // Light is non-functional
218 case lanelet::CarmaTrafficSignalState::STOP_THEN_PROCEED: // Flashing Red
219
220 case lanelet::CarmaTrafficSignalState::PRE_MOVEMENT: // Yellow Red transition (Found only in the EU)
221 // (normally used with arrows)
222 case lanelet::CarmaTrafficSignalState::CAUTION_CONFLICTING_TRAFFIC: // Yellow Flashing
223 default:
224 return false;
225 }
226}
227
229{
230 tf2_listener_ = std::make_shared<tf2_ros::TransformListener>(*tf2_buffer_);
231 tf2_buffer_->setUsingDedicatedThread(true);
232 try
233 {
234 geometry_msgs::msg::TransformStamped tf2 = tf2_buffer_->lookupTransform("base_link", "vehicle_front", rclcpp::Time(0), rclcpp::Duration::from_nanoseconds(20.0 * 1e9)); //save to local copy of transform 20 sec timeout
235 length_to_front_bumper_ = tf2.transform.translation.x;
236 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "length_to_front_bumper_: " << length_to_front_bumper_);
237
238 }
239 catch (const tf2::TransformException &ex)
240 {
241 RCLCPP_WARN_STREAM(rclcpp::get_logger("lci_strategic_plugin"), ex.what());
242 }
243}
244
245LCIStrategicPlugin::VehicleState LCIStrategicPlugin::extractInitialState(carma_planning_msgs::srv::PlanManeuvers::Request::SharedPtr req) const
246{
247 VehicleState state;
248 if (!req->prior_plan.maneuvers.empty())
249 {
250 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Provided with initial plan...");
251 state.stamp = GET_MANEUVER_PROPERTY(req->prior_plan.maneuvers.back(), end_time);
252 state.downtrack = GET_MANEUVER_PROPERTY(req->prior_plan.maneuvers.back(), end_dist);
253 state.speed = GET_MANEUVER_PROPERTY(req->prior_plan.maneuvers.back(), end_speed);
254 state.lane_id = getLaneletsBetweenWithException(state.downtrack, state.downtrack, true).front().id();
255 }
256 else
257 {
258 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "No initial plan provided...");
259
260 state.stamp = rclcpp::Time(req->header.stamp, RCL_SYSTEM_TIME);
261 state.downtrack = req->veh_downtrack;
262 state.speed = req->veh_logitudinal_velocity;
263 state.lane_id = stoi(req->veh_lane_id);
264 }
265 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "extractInitialState >>>> state.stamp: " << std::to_string(state.stamp.seconds()));
266 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "extractInitialState >>>> state.downtrack : " << state.downtrack );
267 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "extractInitialState >>>> state.speed: " << state.speed);
268 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "extractInitialState >>>> state.lane_id: " << state.lane_id);
269
270 return state;
271}
272
273double LCIStrategicPlugin::findSpeedLimit(const lanelet::ConstLanelet& llt) const
274{
275 lanelet::Optional<carma_wm::TrafficRulesConstPtr> traffic_rules = wm_->getTrafficRules();
276 if (traffic_rules)
277 {
278 return (*traffic_rules)->speedLimit(llt).speedLimit.value();
279 }
280 else
281 {
282 throw std::invalid_argument("Valid traffic rules object could not be built");
283 }
284}
285
286bool LCIStrategicPlugin::validLightState(const boost::optional<std::pair<boost::posix_time::ptime, lanelet::CarmaTrafficSignalState>>& optional_state,
287 const rclcpp::Time& source_time) const
288{
289 if (!optional_state)
290 {
291 RCLCPP_WARN_STREAM(rclcpp::get_logger("lci_strategic_plugin"),"Traffic light data not available for source_time " << std::to_string(source_time.seconds()));
292 return false;
293 }
294
295 lanelet::CarmaTrafficSignalState light_state = optional_state.get().second;
296
297 if (!supportedLightState(light_state))
298 {
299 RCLCPP_ERROR_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "LCIStrategic Plugin asked to handle CarmaTrafficSignalState: " << light_state
300 << " which is not supported.");
301 return false;
302 }
303
304 return true;
305}
306
307boost::optional<bool> LCIStrategicPlugin::canArriveAtGreenWithCertainty(const rclcpp::Time& light_arrival_time_by_algo, const lanelet::CarmaTrafficSignalPtr& traffic_light, bool check_late = true, bool check_early = true) const
308{
309 rclcpp::Time early_arrival_time_by_algo =
310 light_arrival_time_by_algo - rclcpp::Duration::from_nanoseconds(config_.green_light_time_buffer * 1e9);
311
312 rclcpp::Time late_arrival_time_by_algo =
313 light_arrival_time_by_algo + rclcpp::Duration::from_nanoseconds(config_.green_light_time_buffer * 1e9);
314
315 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "light_arrival_time_by_algo: " << std::to_string(light_arrival_time_by_algo.seconds()));
316 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "early_arrival_time_by_algo: " << std::to_string(early_arrival_time_by_algo.seconds()));
317 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "late_arrival_time_by_algo: " << std::to_string(late_arrival_time_by_algo.seconds()));
318
319 auto early_arrival_state_by_algo_optional = traffic_light->predictState(lanelet::time::timeFromSec(early_arrival_time_by_algo.seconds()));
320
321 if (!validLightState(early_arrival_state_by_algo_optional, early_arrival_time_by_algo))
322 return boost::none;
323
324 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "early_arrival_state_by_algo: " << early_arrival_state_by_algo_optional.get().second);
325
326 auto late_arrival_state_by_algo_optional = traffic_light->predictState(lanelet::time::timeFromSec(late_arrival_time_by_algo.seconds()));
327
328 if (!validLightState(late_arrival_state_by_algo_optional, late_arrival_time_by_algo))
329 return boost::none;
330
331 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "late_arrival_state_by_algo: " << late_arrival_state_by_algo_optional.get().second);
332
333 bool can_make_early_arrival = true;
334 bool can_make_late_arrival = true;
335
336 if (check_early)
337 can_make_early_arrival = isStateAllowedGreen(early_arrival_state_by_algo_optional.get().second);
338
339 if (check_late)
340 can_make_late_arrival = isStateAllowedGreen(late_arrival_state_by_algo_optional.get().second);
341
342 // We will cross the light on the green phase even if we arrive early or late
343 if (can_make_early_arrival && can_make_late_arrival) // Green light
344 return true;
345 else
346 return false;
347
348}
349
350bool LCIStrategicPlugin::isStateAllowedGreen(const lanelet::CarmaTrafficSignalState& state) const{
351 return state == lanelet::CarmaTrafficSignalState::PROTECTED_MOVEMENT_ALLOWED ||
352 state == lanelet::CarmaTrafficSignalState::PERMISSIVE_MOVEMENT_ALLOWED;
353}
354
355std::vector<lanelet::ConstLanelet> LCIStrategicPlugin::getLaneletsBetweenWithException(double start_downtrack,
356 double end_downtrack,
357 bool shortest_path_only,
358 bool bounds_inclusive) const
359{
360 std::vector<lanelet::ConstLanelet> crossed_lanelets =
361 wm_->getLaneletsBetween(start_downtrack, end_downtrack, shortest_path_only, bounds_inclusive);
362
363 if (crossed_lanelets.size() == 0)
364 {
365 throw std::invalid_argument("getLaneletsBetweenWithException called but inputs do not cross any lanelets going "
366 "from: " +
367 std::to_string(start_downtrack) + " to: " + std::to_string(end_downtrack));
368 }
369
370 return crossed_lanelets;
371}
372
373void LCIStrategicPlugin::handleStopping(carma_planning_msgs::srv::PlanManeuvers::Request::SharedPtr req,
374 carma_planning_msgs::srv::PlanManeuvers::Response::SharedPtr resp,
375 const VehicleState& current_state,
376 const lanelet::CarmaTrafficSignalPtr& traffic_light,
377 const lanelet::ConstLanelet& entry_lanelet, const lanelet::ConstLanelet& exit_lanelet, const lanelet::ConstLanelet& current_lanelet,
378 double traffic_light_down_track,
379 bool is_emergency)
380{
381 double distance_remaining_to_traffic_light = traffic_light_down_track - current_state.downtrack;
382
383 // Identify the lanelets which will be crossed by approach maneuvers lane follow maneuver
384 std::vector<lanelet::ConstLanelet> crossed_lanelets =
385 getLaneletsBetweenWithException(current_state.downtrack, traffic_light_down_track, true, true);
386
387 double decel_rate = max_comfort_decel_norm_; // Kinematic |(v_f - v_i) / t = a|
388
389 if (is_emergency)
390 {
391 decel_rate = emergency_decel_norm_;
393 }
394 else
395 {
397 }
398
399 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "HANDLE_STOPPING: Planning stop and wait maneuver at decel_rate: " << decel_rate);
400
401 resp->new_plan.maneuvers.push_back(composeStopAndWaitManeuverMessage(
402 current_state.downtrack, traffic_light_down_track, current_state.speed, crossed_lanelets.front().id(),
403 crossed_lanelets.back().id(), current_state.stamp,
404 current_state.stamp + rclcpp::Duration::from_nanoseconds(config_.min_maneuver_planning_period * 1e9), decel_rate));
405}
406
407
408void LCIStrategicPlugin::handleFailureCase(carma_planning_msgs::srv::PlanManeuvers::Request::SharedPtr req,
409 carma_planning_msgs::srv::PlanManeuvers::Response::SharedPtr resp,
410 const VehicleState& current_state,
411 double current_state_speed,
412 double speed_limit,
413 double remaining_time,
414 lanelet::Id exit_lanelet_id,
415 const lanelet::CarmaTrafficSignalPtr& traffic_light,
416 double traffic_light_down_track, const TrajectoryParams& ts_params)
417{
418 double distance_remaining_to_traffic_light = traffic_light_down_track - current_state.downtrack;
419
420 // Identify the lanelets which will be crossed by approach maneuvers lane follow maneuver
421 std::vector<lanelet::ConstLanelet> crossed_lanelets =
422 getLaneletsBetweenWithException(current_state.downtrack, traffic_light_down_track, true, true);
423
424 auto incomplete_traj_params = handleFailureCaseHelper(traffic_light, current_state.stamp.seconds(), current_state_speed, intersection_speed_.get(), speed_limit, distance_remaining_to_traffic_light, traffic_light_down_track);
425
426 if (incomplete_traj_params.is_algorithm_successful == false)
427 {
428 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Failed to generate maneuver for edge cases...");
429 return;
430 }
431
432 resp->new_plan.maneuvers.push_back(composeTrajectorySmoothingManeuverMessage(current_state.downtrack, traffic_light_down_track, crossed_lanelets,
433 current_state_speed, incomplete_traj_params.modified_departure_speed, current_state.stamp, current_state.stamp + rclcpp::Duration::from_nanoseconds(incomplete_traj_params.modified_remaining_time * 1e9), incomplete_traj_params));
434
435 double intersection_length = intersection_end_downtrack_.get() - traffic_light_down_track;
436
437 rclcpp::Time intersection_exit_time =
438 current_state.stamp + rclcpp::Duration::from_nanoseconds(incomplete_traj_params.modified_remaining_time * 1e9) + rclcpp::Duration::from_nanoseconds(intersection_length / incomplete_traj_params.modified_departure_speed * 1e9);
439
440 resp->new_plan.maneuvers.push_back(composeIntersectionTransitMessage(
441 traffic_light_down_track, intersection_end_downtrack_.get(), intersection_speed_.get(),
442 incomplete_traj_params.modified_departure_speed, current_state.stamp + rclcpp::Duration::from_nanoseconds(incomplete_traj_params.modified_remaining_time * 1e9), intersection_exit_time, crossed_lanelets.back().id(), crossed_lanelets.back().id()));
443
445}
446
447void LCIStrategicPlugin::handleCruisingUntilStop(carma_planning_msgs::srv::PlanManeuvers::Request::SharedPtr req,
448 carma_planning_msgs::srv::PlanManeuvers::Response::SharedPtr resp,
449 const VehicleState& current_state,
450 double current_state_speed,
451 const lanelet::CarmaTrafficSignalPtr& traffic_light,
452 double traffic_light_down_track, const TrajectoryParams& ts_params)
453{
454 if (!ts_params.is_algorithm_successful || ts_params.case_num != TSCase::CASE_8)
455 {
456 RCLCPP_WARN_STREAM(rclcpp::get_logger("lci_strategic_plugin"),"handleCruisingUntilStop is called but it is not case_8");
457 return;
458 }
459
460 auto new_ts_params = ts_params;
461
462 double decel_rate = std::fabs(ts_params.a3_);
463
464 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "CASE_8: Planning cruise and stop with decel_rate: " << decel_rate);
465
466 new_ts_params.t3_ = new_ts_params.t2_;
467 new_ts_params.x3_ = new_ts_params.x2_;
468 new_ts_params.v3_ = new_ts_params.v2_;
469 new_ts_params.a3_ = new_ts_params.a2_;
470
471 // Identify the lanelets which will be crossed by approach maneuvers stopping part
472 std::vector<lanelet::ConstLanelet> lane_follow_crossed_lanelets =
473 getLaneletsBetweenWithException(new_ts_params.x1_, new_ts_params.x2_, true, true);
474
475 resp->new_plan.maneuvers.push_back(composeTrajectorySmoothingManeuverMessage(current_state.downtrack, new_ts_params.x2_, lane_follow_crossed_lanelets,
476 current_state_speed, new_ts_params.v2_, current_state.stamp, rclcpp::Time(new_ts_params.t2_ * 1e9), new_ts_params));
477
478 // Identify the lanelets which will be crossed by approach maneuvers stopping part
479 std::vector<lanelet::ConstLanelet> case_8_crossed_lanelets =
480 getLaneletsBetweenWithException(new_ts_params.x2_, traffic_light_down_track, true, true);
481
482 resp->new_plan.maneuvers.push_back(composeStopAndWaitManeuverMessage(
483 new_ts_params.x2_, traffic_light_down_track, new_ts_params.v2_, case_8_crossed_lanelets.front().id(),
484 case_8_crossed_lanelets.back().id(), rclcpp::Time(new_ts_params.t2_ * 1e9),
485 rclcpp::Time(new_ts_params.t2_ * 1e9) + rclcpp::Duration::from_nanoseconds(config_.min_maneuver_planning_period * 1e9), decel_rate));
486
487 return;
488}
489
490void LCIStrategicPlugin::handleGreenSignalScenario(carma_planning_msgs::srv::PlanManeuvers::Request::SharedPtr req,
491 carma_planning_msgs::srv::PlanManeuvers::Response::SharedPtr resp,
492 const VehicleState& current_state,
493 double current_state_speed,
494 const lanelet::CarmaTrafficSignalPtr& traffic_light,
495 const lanelet::ConstLanelet& entry_lanelet, const lanelet::ConstLanelet& exit_lanelet,
496 double traffic_light_down_track, const TrajectoryParams& ts_params, bool is_certainty_check_optional)
497{
498 if (!ts_params.is_algorithm_successful || ts_params.case_num == TSCase::CASE_8)
499 {
500 return;
501 }
502
503 rclcpp::Time light_arrival_time_by_algo = rclcpp::Time(ts_params.t3_ * 1e9);
504 double remaining_time = light_arrival_time_by_algo.seconds() - rclcpp::Time(req->header.stamp, RCL_SYSTEM_TIME).seconds();
505 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Algo initially successful: New light_arrival_time_by_algo: " << std::to_string(light_arrival_time_by_algo.seconds()) << ", with remaining_time: " << std::to_string(remaining_time));
506 auto can_make_green_optional = canArriveAtGreenWithCertainty(light_arrival_time_by_algo, traffic_light);
507
508 // Identify the lanelets which will be crossed by approach maneuvers lane follow maneuver
509 std::vector<lanelet::ConstLanelet> crossed_lanelets =
510 getLaneletsBetweenWithException(current_state.downtrack, traffic_light_down_track, true, true);
511
512 // no change for maneuver if invalid light states
513 if (!can_make_green_optional)
514 return;
515
516 if (can_make_green_optional.get() || is_certainty_check_optional)
517 {
518 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "HANDLE_SUCCESSFULL: Algorithm successful, and able to make it at green with certainty. Planning traj smooth and intersection transit maneuvers");
519
520 resp->new_plan.maneuvers.push_back(composeTrajectorySmoothingManeuverMessage(current_state.downtrack, traffic_light_down_track, crossed_lanelets,
521 current_state_speed, ts_params.v3_, current_state.stamp, light_arrival_time_by_algo, ts_params));
522
523 double intersection_length = intersection_end_downtrack_.get() - traffic_light_down_track;
524
525 rclcpp::Time intersection_exit_time =
526 light_arrival_time_by_algo + rclcpp::Duration::from_nanoseconds(intersection_length / intersection_speed_.get() * 1e9);
527
528 resp->new_plan.maneuvers.push_back(composeIntersectionTransitMessage(
529 traffic_light_down_track, intersection_end_downtrack_.get(), intersection_speed_.get(),
530 intersection_speed_.get(), light_arrival_time_by_algo, intersection_exit_time, crossed_lanelets.back().id(), crossed_lanelets.back().id()));
531 }
532}
533
534
535TrajectoryParams LCIStrategicPlugin::handleFailureCaseHelper(const lanelet::CarmaTrafficSignalPtr& traffic_light, double current_time, double starting_speed, double departure_speed, double speed_limit, double remaining_downtrack, double traffic_light_downtrack)
536{
537 //Requested maneuver needs to be modified to meet remaining_dist req
538 //by trying to get close to the target_speed and remaining_time as much as possible
539 TrajectoryParams return_params;
540 TrajectoryParams traj_upper;
541 TrajectoryParams traj_lower;
542
543 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "HANDLE_LAST_RESORT_CASE: Starting...");
544 double starting_downtrack = traffic_light_downtrack - remaining_downtrack;
545 double modified_remaining_time_upper; // upper meaning downtrack vs time trajectory is curved upwards
546 double modified_remaining_time_lower; // lower meaning downtrack vs time trajectory is curved lower
547 double modified_departure_speed_upper;
548 double modified_departure_speed_lower;
549 bool calculation_success_upper = true; // identifies places in codes where calculation can be invalid such as negative distance
550
551 // the upper ET
552 // accel case
553 traj_upper.t0_ = current_time;
554 traj_upper.v0_ = starting_speed;
555 traj_upper.x0_ = starting_downtrack;
556 traj_upper.is_algorithm_successful = true;
557 traj_upper.case_num = CASE_1;
558
559 if (departure_speed >= starting_speed)
560 {
561 if ((pow(departure_speed,2) - pow(starting_speed,2))/(2*max_comfort_accel_) >= remaining_downtrack)
562 {
563 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "HandleFailureCase -> Upper Trajectory -> Current Speed <= Desired Departure Speed, Actual Departure Speed < Desired Departure Speed");
564
565 modified_departure_speed_upper = sqrt(pow(starting_speed, 2) + (2 * max_comfort_accel_ * remaining_downtrack));
566 modified_remaining_time_upper = (modified_departure_speed_upper - starting_speed) / max_comfort_accel_;
567
568 traj_upper.t1_ = current_time + modified_remaining_time_upper;
569 traj_upper.v1_ = modified_departure_speed_upper;
570 traj_upper.a1_ = max_comfort_accel_;
571 traj_upper.x1_ = traffic_light_downtrack;
572
573 traj_upper.t2_ = traj_upper.t1_;
574 traj_upper.v2_ = traj_upper.v1_;
575 traj_upper.a2_ = traj_upper.a1_;
576 traj_upper.x2_ = traj_upper.x1_;
577
578 traj_upper.modified_departure_speed = modified_departure_speed_upper;
579 traj_upper.modified_remaining_time = modified_remaining_time_upper;
580 }
581 else // NOTE: most likely will not happen as it would have happened at trajectory smoothing part
582 {
583 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "HandleFailureCase -> Upper Trajectory -> Current Speed < Desired Departure Speed, Actual Departure Speed = Desired Departure Speed");
584
585 double cruising_distance = remaining_downtrack - (pow(departure_speed, 2) - pow(starting_speed, 2))/ ( 2 * max_comfort_accel_);
586 if (cruising_distance < -EPSILON)
587 {
588 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Detected calculation failure in upper case 2");
589 calculation_success_upper = false;
590 }
591 modified_remaining_time_upper = ((departure_speed - starting_speed) / max_comfort_accel_) + (cruising_distance / departure_speed);
592
593 traj_upper.t1_ = current_time + ((departure_speed - starting_speed) / max_comfort_accel_);
594 traj_upper.v1_ = departure_speed;
595 traj_upper.a1_ = max_comfort_accel_;
596 traj_upper.x1_ = starting_downtrack + (pow(departure_speed, 2) - pow(starting_speed, 2)) / (2 * max_comfort_accel_);
597
598 traj_upper.t2_ = current_time + modified_remaining_time_upper;
599 traj_upper.v2_ = departure_speed;
600 traj_upper.a2_ = 0;
601 traj_upper.x2_ = traffic_light_downtrack;
602
603 traj_upper.modified_departure_speed = departure_speed;
604 traj_upper.modified_remaining_time = modified_remaining_time_upper;
605 }
606 }
607
608 if (departure_speed < starting_speed) // NOTE: most cases will not run due to departure speed being equal to speed limit
609 {
610 if ((pow(departure_speed,2) - pow(starting_speed,2))/(2*max_comfort_decel_) >= remaining_downtrack)
611 {
612 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "HandleFailureCase -> Upper Trajectory -> Current Speed > Desired Departure Speed, Actual Departure Speed > Desired Departure Speed");
613
614 modified_departure_speed_upper = sqrt(pow(starting_speed, 2) + (2 * max_comfort_decel_ * remaining_downtrack));
615 modified_remaining_time_upper = (modified_departure_speed_upper - starting_speed) / max_comfort_decel_;
616
617 traj_upper.t1_ = current_time + modified_remaining_time_upper;
618 traj_upper.v1_ = modified_departure_speed_upper;
619 traj_upper.a1_ = max_comfort_decel_;
620 traj_upper.x1_ = traffic_light_downtrack;
621
622 traj_upper.t2_ = traj_upper.t1_;
623 traj_upper.v2_ = traj_upper.v1_;
624 traj_upper.a2_ = traj_upper.a1_;
625 traj_upper.x2_ = traj_upper.x1_;
626
627 traj_upper.modified_departure_speed = modified_departure_speed_upper;
628 traj_upper.modified_remaining_time = modified_remaining_time_upper;
629 }
630 else // NOTE: most likely will not happen as it would have happened at trajectory smoothing part
631 {
632 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "HandleFailureCase -> Upper Trajectory -> Current Speed > Desired Departure Speed, Actual Departure Speed = Desired Departure Speed");
633
634 double cruising_distance = remaining_downtrack - (pow(departure_speed, 2) - pow(starting_speed, 2))/ ( 2 * max_comfort_decel_);
635
636 if (cruising_distance < -EPSILON)
637 {
638 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Detected calculation failure in upper case 4");
639 calculation_success_upper = false;
640 }
641
642 modified_remaining_time_upper = cruising_distance / starting_speed + (departure_speed - starting_speed) / max_comfort_decel_ ;
643
644 traj_upper.t1_ = current_time + cruising_distance / starting_speed;
645 traj_upper.v1_ = starting_speed;
646 traj_upper.a1_ = 0.0;
647 traj_upper.x1_ = starting_downtrack + cruising_distance;
648
649 traj_upper.t2_ = current_time + modified_remaining_time_upper;
650 traj_upper.v2_ = departure_speed;
651 traj_upper.a2_ = max_comfort_decel_;
652 traj_upper.x2_ = traffic_light_downtrack;
653
654 traj_upper.modified_departure_speed = departure_speed;
655 traj_upper.modified_remaining_time = modified_remaining_time_upper;
656 }
657 }
658
659 traj_upper.t3_ = traj_upper.t2_;
660 traj_upper.v3_ = traj_upper.v2_;
661 traj_upper.a3_ = traj_upper.a2_;
662 traj_upper.x3_ = traj_upper.x2_;
663
664 // The lower ET
665 // (note that the distance is definitely not enough for deceleration to zero speed, therefore, modified_departure_speed will be greater than zero for sure!).
666 modified_departure_speed_lower = sqrt(pow(starting_speed, 2) + (2 * max_comfort_decel_ * remaining_downtrack));
667 modified_remaining_time_lower = (modified_departure_speed_lower - starting_speed) / max_comfort_decel_;
668
669 traj_lower.t0_ = current_time;
670 traj_lower.v0_ = starting_speed;
671 traj_lower.x0_ = starting_downtrack;
672 traj_lower.is_algorithm_successful = true;
673 traj_lower.case_num = CASE_1;
674
675 traj_lower.t1_ = current_time + modified_remaining_time_lower;
676 traj_lower.v1_ = modified_departure_speed_lower;
677 traj_lower.a1_ = max_comfort_decel_;
678 traj_lower.x1_ = traffic_light_downtrack;
679
680 traj_lower.t2_ = traj_lower.t1_;
681 traj_lower.v2_ = traj_lower.v1_;
682 traj_lower.a2_ = traj_lower.a1_;
683 traj_lower.x2_ = traj_lower.x1_;
684
685 traj_lower.t3_ = traj_lower.t2_;
686 traj_lower.v3_ = traj_lower.v2_;
687 traj_lower.a3_ = traj_lower.a2_;
688 traj_lower.x3_ = traj_lower.x2_;
689
690 traj_lower.modified_departure_speed = modified_departure_speed_lower;
691 traj_lower.modified_remaining_time = modified_remaining_time_upper;
692
693 // Pick UPPER or LOWER trajectory based on light
694 bool is_return_params_found = false;
695
696 if (calculation_success_upper)
697 {
698 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Checking this time!: " << current_time + modified_remaining_time_upper);
699
700 auto upper_optional = traffic_light->predictState(lanelet::time::timeFromSec(current_time + modified_remaining_time_upper));
701
702 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Checking this time! state: " << upper_optional.get().second);
703
704 if (!validLightState(upper_optional, rclcpp::Time((current_time + modified_remaining_time_upper) * 1e9)))
705 {
706 RCLCPP_ERROR_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Unable to resolve give signal for modified_remaining_time_upper: " << std::to_string(current_time + modified_remaining_time_upper));
707 }
708 else
709 {
710 if (isStateAllowedGreen(upper_optional.get().second))
711 {
712 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Detected Upper GREEN case");
713 return_params = traj_upper;
714 is_return_params_found = true;
715 }
716 }
717 }
718
719 if (!is_return_params_found)
720 {
721 auto lower_optional = traffic_light->predictState(lanelet::time::timeFromSec(current_time + modified_remaining_time_lower));
722
723 if (!validLightState(lower_optional, rclcpp::Time((current_time + modified_remaining_time_lower) * 1e9)))
724 {
725 RCLCPP_ERROR_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Unable to resolve give signal for modified_remaining_time_lower:" << std::to_string(current_time + modified_remaining_time_lower));
726 }
727 else
728 {
729 if (isStateAllowedGreen(lower_optional.get().second))
730 {
731 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Detected Lower GREEN case");
732 return_params = traj_lower;
733 is_return_params_found = true;
734 }
735 }
736 }
737
738 // Handle hard failure case such as nan or invalid states
739 if (is_return_params_found && !isnan(return_params.modified_departure_speed) && return_params.modified_departure_speed > epsilon_ &&
740 return_params.modified_departure_speed < speed_limit ) //80_mph
741 {
742 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Updated the speed, and using modified_departure_speed: " << return_params.modified_departure_speed);
743 print_params(return_params);
744 return return_params;
745 }
746 else
747 {
748 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Unable to handle edge case gracefully");
749 return_params = TrajectoryParams(); //reset
750 return_params.is_algorithm_successful = false;
751 return return_params;
752 }
753}
754
755
756void LCIStrategicPlugin::planWhenUNAVAILABLE(carma_planning_msgs::srv::PlanManeuvers::Request::SharedPtr req,
757 carma_planning_msgs::srv::PlanManeuvers::Response::SharedPtr resp, const VehicleState& current_state,
758 const lanelet::CarmaTrafficSignalPtr& traffic_light, const lanelet::ConstLanelet& entry_lanelet, const lanelet::ConstLanelet& exit_lanelet, const lanelet::ConstLanelet& current_lanelet)
759{
760 // Reset intersection state since in this state we are not yet known to be in or approaching an intersection
761 intersection_speed_ = boost::none;
762 intersection_end_downtrack_ = boost::none;
763 double current_state_speed = std::max(current_state.speed, config_.algo_minimum_speed * 1.001);
764
765
766 if (!traffic_light)
767 {
768 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "No lights found along route. Returning maneuver plan unchanged");
769 return;
770 }
771
773 double max_comfort_decel = -1.0 * config_.vehicle_decel_limit * config_.vehicle_decel_limit_multiplier;
774
775 auto stop_line = traffic_light->getStopLine(entry_lanelet);
776
777 if (!stop_line)
778 {
779 throw std::invalid_argument("Given entry lanelet doesn't have stop_line...");
780 }
781
782 double traffic_light_down_track =
783 wm_->routeTrackPos(stop_line.get().front().basicPoint2d()).downtrack;
784
785 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "traffic_light_down_track: " << traffic_light_down_track);
786
787 double distance_remaining_to_traffic_light = traffic_light_down_track - current_state.downtrack;
788
789 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "distance_remaining_to_traffic_light: " << distance_remaining_to_traffic_light <<
790 ", current_state.downtrack: " << current_state.downtrack);
791
792 distance_remaining_to_tf_ = distance_remaining_to_traffic_light; // performance metric
793
794 auto speed_limit = findSpeedLimit(current_lanelet);
795
796 current_state_speed = std::min(speed_limit, current_state_speed);
797
798 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "speed_limit (free flow speed): " << speed_limit);
799
800 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "trajectory_smoothing_activation_distance: " << config_.trajectory_smoothing_activation_distance);
801
802 double stopping_dist = estimate_distance_to_stop(current_state_speed, config_.vehicle_decel_limit_multiplier *
803 config_.vehicle_decel_limit); //accepts positive decel
804
805 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Stopping distance: " << stopping_dist);
806
807 double plugin_activation_distance = std::max(stopping_dist, config_.min_approach_distance);
808
809 plugin_activation_distance = std::max(plugin_activation_distance, config_.trajectory_smoothing_activation_distance);
810
811 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "plugin_activation_distance: " << plugin_activation_distance);
812
813 if (distance_remaining_to_traffic_light <= plugin_activation_distance)
814 {
815 RCLCPP_INFO_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Within intersection range");
816 transition_table_.signal(TransitEvent::IN_STOPPING_RANGE); // Evaluate Signal and Run Trajectory Smoothing Algorithm
817 }
818 else
819 {
821 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Not within intersection range");
822 }
823
824}
825
826void LCIStrategicPlugin::planWhenAPPROACHING(carma_planning_msgs::srv::PlanManeuvers::Request::SharedPtr req,
827 carma_planning_msgs::srv::PlanManeuvers::Response::SharedPtr resp, const VehicleState& current_state,
828 const lanelet::CarmaTrafficSignalPtr& traffic_light, const lanelet::ConstLanelet& entry_lanelet, const lanelet::ConstLanelet& exit_lanelet, const lanelet::ConstLanelet& current_lanelet)
829{
831
832 if (!traffic_light) // If we are in the approaching state and there is no longer any lights ahead of us then
833 // the vehicle must have crossed the stop bar
834 {
836 return;
837 }
838
839 double current_state_speed = std::max(current_state.speed, config_.algo_minimum_speed * 1.001);
840
841 auto stop_line = traffic_light->getStopLine(entry_lanelet);
842
843 if (!stop_line)
844 {
845 throw std::invalid_argument("Given entry lanelet doesn't have stop_line...");
846 }
847
848 double traffic_light_down_track =
849 wm_->routeTrackPos(stop_line.get().front().basicPoint2d()).downtrack;
850
851 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "traffic_light_down_track: " << traffic_light_down_track);
852
853 double distance_remaining_to_traffic_light = traffic_light_down_track - current_state.downtrack;
854
855 distance_remaining_to_tf_ = distance_remaining_to_traffic_light;
856
857 if (distance_remaining_to_traffic_light < 0) // there is small discrepancy between signal's routeTrackPos as well as current
858 { // downtrack calculated using veh_x,y from state. Therefore, it may have crossed it
859 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Crossed the bar distance_remaining_to_traffic_light: " << distance_remaining_to_traffic_light);
861 return;
862 }
863
864 // At this point we know the vehicle is within the activation distance and we know the current and next light phases
865 // All we need to now determine is if we should stop or if we should continue
866 lanelet::ConstLanelet intersection_lanelet;
867
868 auto route = wm_->getRoute()->shortestPath();
869 auto entry_llt_iter = std::find(route.begin(), route.end(), entry_lanelet);
870 if (entry_llt_iter != route.end())
871 {
872 intersection_lanelet = *(entry_llt_iter + 1);
873 }
874
875 if (intersection_lanelet.id() != lanelet::InvalId)
876 {
877 intersection_speed_ = findSpeedLimit(intersection_lanelet);
879 }
880 else
881 {
882 intersection_speed_ = findSpeedLimit(exit_lanelet);
883 }
884
885 intersection_speed_ = intersection_speed_.get() * 0.999; // so that speed_limit is not exactly same as departure or current speed
886
887 double speed_limit = findSpeedLimit(current_lanelet);
888
889 current_state_speed = std::min(current_state_speed, speed_limit - 5 * epsilon_); // so that current_speed is not exactly same as departure or speed limit
890
891 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "current_state_speed: " << current_state_speed);
892 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "intersection_speed_: " << intersection_speed_.get());
893 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "distance_remaining_to_traffic_light: " << distance_remaining_to_traffic_light);
894
896 wm_->routeTrackPos(exit_lanelet.centerline2d().front().basicPoint2d()).downtrack;
897
898 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "intersection_end_downtrack_: " << intersection_end_downtrack_.get());
899
900 // If the vehicle is at a stop trigger the stopped state
901 constexpr double HALF_MPH_IN_MPS = 0.22352;
902 if (current_state.speed < HALF_MPH_IN_MPS &&
903 fabs(distance_remaining_to_traffic_light) < config_.stopping_location_buffer)
904 {
905 transition_table_.signal(TransitEvent::STOPPED); // The vehicle has come to a stop at the light
906 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "CARMA has detected that the vehicle stopped at the stop bar. Transitioning to WAITING STATE");
907
908 return;
909 }
910
912
913 rclcpp::Time earliest_entry_time = current_state.stamp + get_earliest_entry_time(distance_remaining_to_traffic_light, speed_limit,
914 current_state_speed, intersection_speed_.get(), max_comfort_accel_, max_comfort_decel_);
915
916 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "earliest_entry_time: " << std::to_string(earliest_entry_time.seconds()) << ", with : " << std::to_string((earliest_entry_time - current_state.stamp).seconds()) << " left at: " << std::to_string(current_state.stamp.seconds()));
917
918 auto [nearest_green_entry_time, is_entry_time_within_green_or_tbd, in_tbd] = get_final_entry_time_and_conditions(current_state, earliest_entry_time, traffic_light);
919
920 if (nearest_green_entry_time == rclcpp::Time(0))
921 return;
922
923 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Final nearest_green_entry_time: " << std::to_string(nearest_green_entry_time.seconds()));
924
925 auto et_state = traffic_light->predictState(lanelet::time::timeFromSec(nearest_green_entry_time.seconds()));
926 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Signal at ET: " << et_state.get().second);
927
929
930 double remaining_time = nearest_green_entry_time.seconds() - current_state.stamp.seconds();
931 double remaining_time_earliest_entry = earliest_entry_time.seconds() - current_state.stamp.seconds();
932 scheduled_entry_time_ = remaining_time; // performance metric
933 earliest_entry_time_ = remaining_time_earliest_entry; // performance metric
934
935 auto boundary_distances = get_delta_x(current_state_speed, intersection_speed_.get(), speed_limit, config_.algo_minimum_speed, max_comfort_accel_, max_comfort_decel_);
936 print_boundary_distances(boundary_distances); //debug
937
938 auto boundary_traj_params = get_boundary_traj_params(rclcpp::Time(req->header.stamp, RCL_SYSTEM_TIME).seconds(), current_state_speed, intersection_speed_.get(), speed_limit, config_.algo_minimum_speed, max_comfort_accel_, max_comfort_decel_, current_state.downtrack, traffic_light_down_track, distance_remaining_to_traffic_light, boundary_distances);
939
940 TrajectoryParams ts_params = get_ts_case(rclcpp::Time(req->header.stamp, RCL_SYSTEM_TIME).seconds(), nearest_green_entry_time.seconds(), current_state_speed, intersection_speed_.get(), speed_limit, config_.algo_minimum_speed, max_comfort_accel_, max_comfort_decel_, current_state.downtrack, traffic_light_down_track, distance_remaining_to_traffic_light, boundary_distances, boundary_traj_params);
941 print_params(ts_params);
942
943 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "SPEED PROFILE CASE:" << ts_params.case_num);
944
946 double emergency_distance_to_stop = pow(current_state.speed, 2)/(2 * emergency_decel_norm_) + config_.stopping_location_buffer / 2; //Idea is to aim the middle part of stopping buffer
947 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "emergency_distance_to_stop at emergency_decel_norm_ (with stopping_location_buffer/2): " << emergency_distance_to_stop << ", emergency_decel_norm_: " << emergency_decel_norm_);
948
949 double safe_distance_to_stop = pow(current_state.speed, 2)/(2 * max_comfort_decel_norm_) + config_.stopping_location_buffer / 2; //Idea is to aim the middle part of stopping buffer
950 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "safe_distance_to_stop at max_comfort_decel (with stopping_location_buffer/2): " << safe_distance_to_stop << ", max_comfort_decel_norm_: " << max_comfort_decel_norm_);
951
952 double desired_distance_to_stop = pow(current_state.speed, 2)/(2 * max_comfort_decel_norm_ * config_.deceleration_fraction) + config_.desired_distance_to_stop_buffer;
953 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "desired_distance_to_stop at: " << desired_distance_to_stop << ", where effective deceleration rate is: " << max_comfort_decel_norm_ * config_.deceleration_fraction);
954
955 emergency_distance_to_stop = std::max(emergency_distance_to_stop, config_.stopping_location_buffer);
956 safe_distance_to_stop = std::max(safe_distance_to_stop, config_.stopping_location_buffer);
957 desired_distance_to_stop = std::max(desired_distance_to_stop, config_.stopping_location_buffer);
958
959 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "new emergency_distance_to_stop: " << emergency_distance_to_stop);
960 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "new safe_distance_to_stop: " << safe_distance_to_stop);
961 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "new desired_distance_to_stop: " << desired_distance_to_stop);
962
963 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "distance_remaining_to_traffic_light: " << distance_remaining_to_traffic_light << ", current_state.speed: " << current_state.speed);
964
965 // Basic RED signal violation check
966 if (distance_remaining_to_traffic_light <= emergency_distance_to_stop || last_case_num_ == TSCase::EMERGENCY_STOPPING)
967 {
968 if (in_tbd) // Given ET is in TBD, but vehicle is too close to intersection
969 {
970 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "ET is still in TBD despite the vehicle being in desired distance to start stopping. Trying to handle this edge case gracefully...");
971 }
972
973 double stopping_time = current_state.speed / 1.5 / max_comfort_decel_norm_; //one half the acceleration (twice the acceleration to stop) to account for emergency case, see emergency_decel_norm_
974
975 rclcpp::Time stopping_arrival_time =
976 current_state.stamp + rclcpp::Duration::from_nanoseconds(stopping_time * 1e9);
977
978 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "stopping_arrival_time: " << std::to_string(stopping_arrival_time.seconds()));
979
980 auto stopping_arrival_state_optional = traffic_light->predictState(lanelet::time::timeFromSec(stopping_arrival_time.seconds()));
981
982 if (!validLightState(stopping_arrival_state_optional, stopping_arrival_time))
983 {
984 RCLCPP_ERROR_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Unable to resolve give signal for stopping_arrival_state_optional: " << std::to_string(stopping_arrival_time.seconds()));
985 return;
986 }
987
988 if (stopping_arrival_state_optional.get().second == lanelet::CarmaTrafficSignalState::STOP_AND_REMAIN || last_case_num_ == TSCase::EMERGENCY_STOPPING) // if once started emergency stopped, keep doing it to avoid jerkiness
989 {
990 RCLCPP_WARN_STREAM(rclcpp::get_logger("lci_strategic_plugin"),"Detected possible RED light violation! Stopping!");
991 handleStopping(req,resp, current_state, traffic_light, entry_lanelet, exit_lanelet, current_lanelet, traffic_light_down_track, true); //case_11
993
994 return;
995 }
996 }
997
998 // Check if the vehicle can arrive with certainty (Case 1-7)
999 if (ts_params.is_algorithm_successful && ts_params.case_num != TSCase::CASE_8 &&
1000 (distance_remaining_to_traffic_light >= desired_distance_to_stop || !in_tbd) &&
1001 is_entry_time_within_green_or_tbd) // ET cannot be explicitly inside RED or YELLOW in available future states, which is ERROR case
1002 {
1003 handleGreenSignalScenario(req, resp, current_state, current_state_speed, traffic_light, entry_lanelet, exit_lanelet, traffic_light_down_track, ts_params, in_tbd); //in_tbd means optional to check certainty arrival at green
1004
1005 if (!resp->new_plan.maneuvers.empty()) // able to pass at green
1006 {
1007 last_case_num_ = ts_params.case_num;
1008 return;
1009 }
1010
1011 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Not able to make it with certainty: TSCase: " << ts_params.case_num << ", changing it to 8");
1012 ts_params = boundary_traj_params[7];
1013 ts_params.is_algorithm_successful = true; //false correspond to cases when vehicle is beyond safe_distance to stop for case8
1014 ts_params.case_num = CASE_8;
1015 print_params(ts_params);
1016 }
1017
1018 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Not able to make it with certainty: NEW TSCase: " << ts_params.case_num);
1019 // if algorithm is NOT successful or if the vehicle cannot make the green light with certainty
1020
1021 if (desired_distance_to_stop < distance_remaining_to_traffic_light && last_case_num_ != TSCase::STOPPING) // do not switch from STOPPING to case8 again
1022 {
1023 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Way too early to stop. Cruising at CASE8");
1024 handleCruisingUntilStop(req, resp, current_state, current_state_speed, traffic_light, traffic_light_down_track, ts_params);
1025
1026 if (!resp->new_plan.maneuvers.empty())
1027 {
1029 return;
1030 }
1031 }
1032
1033 if ((safe_distance_to_stop <= distance_remaining_to_traffic_light && desired_distance_to_stop >= distance_remaining_to_traffic_light) ||
1034 last_case_num_ == TSCase::STOPPING) // if stopping continue stopping until transition to planwhenWAITING
1035 {
1036 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Planning stopping now. last case:" << static_cast<int>(last_case_num_));
1037 handleStopping(req,resp, current_state, traffic_light, entry_lanelet, exit_lanelet, current_lanelet, traffic_light_down_track); //case_9
1038 return;
1039 }
1040
1041 if (safe_distance_to_stop > distance_remaining_to_traffic_light)
1042 {
1043 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "No longer within safe distance to stop! Decide to continue stopping or continue into intersection");
1044
1045 if (last_case_num_ != TSCase::STOPPING && last_case_num_ != TSCase::UNAVAILABLE && last_case_num_ != TSCase::CASE_8) //case 1-7 or emergency stop or handlefailure
1046 {
1047 // 3. if not able to stop nor reach target speed at green, attempt its best to reach the target parameters at the intersection
1048 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "HANDLE_LAST_RESORT: The vehicle is not able to stop at red/yellow light nor is able to reach target speed at green. Attempting its best to pass through at green!");
1049
1050 handleFailureCase(req, resp, current_state, current_state_speed, speed_limit, remaining_time,
1051 exit_lanelet.id(), traffic_light, traffic_light_down_track, ts_params);
1052
1053 if (resp->new_plan.maneuvers.empty())
1054 {
1055 RCLCPP_WARN_STREAM(rclcpp::get_logger("lci_strategic_plugin"),"HANDLE_SAFETY: Planning forced slow-down... last case:" << static_cast<int>(last_case_num_));
1056 handleStopping(req,resp, current_state, traffic_light, entry_lanelet, exit_lanelet, current_lanelet, traffic_light_down_track, true); //case_11 emergency case with twice the normal deceleration
1057 }
1058 }
1059 else
1060 {
1061 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "HANDLE_SAFETY: Planning to keep stopping now. last case:" << static_cast<int>(last_case_num_));
1062 handleStopping(req,resp, current_state, traffic_light, entry_lanelet, exit_lanelet, current_lanelet, traffic_light_down_track); //case_9
1063 }
1064 }
1065
1066
1067}
1068
1069void LCIStrategicPlugin::planWhenWAITING(carma_planning_msgs::srv::PlanManeuvers::Request::SharedPtr req,
1070 carma_planning_msgs::srv::PlanManeuvers::Response::SharedPtr resp, const VehicleState& current_state,
1071 const lanelet::CarmaTrafficSignalPtr& traffic_light, const lanelet::ConstLanelet& entry_lanelet, const lanelet::ConstLanelet& exit_lanelet, const lanelet::ConstLanelet& current_lanelet)
1072{
1074
1075 if (!traffic_light)
1076 {
1077 throw std::invalid_argument("While in WAITING state, the traffic lights disappeared.");
1078 }
1079
1080 auto stop_line = traffic_light->getStopLine(entry_lanelet);
1081
1082 if (!stop_line)
1083 {
1084 throw std::invalid_argument("Given entry lanelet doesn't have stop_line...");
1085 }
1086
1087 double traffic_light_down_track =
1088 wm_->routeTrackPos(stop_line.get().front().basicPoint2d()).downtrack;
1089
1090 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "traffic_light_down_track: "<< traffic_light_down_track);
1091
1092 double entering_time = current_state.stamp.seconds();
1093
1094 auto current_light_state_optional = traffic_light->predictState(lanelet::time::timeFromSec(entering_time));
1095
1096 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "WAITING STATE: requested time to rclcpp::Time(req->header.stamp, RCL_SYSTEM_TIME) check: " << std::to_string(rclcpp::Time(req->header.stamp, RCL_SYSTEM_TIME).seconds()));
1097 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "WAITING STATE: requested time to CURRENT STATE check: " << std::to_string(entering_time));
1098
1099 if (!validLightState(current_light_state_optional, rclcpp::Time(entering_time * 1e9)))
1100 return;
1101
1102 auto bool_optional_late_certainty = canArriveAtGreenWithCertainty(rclcpp::Time(entering_time * 1e9), traffic_light, true, false);
1103
1104 if (!bool_optional_late_certainty)
1105 {
1106 RCLCPP_ERROR_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Unable to resolve green light...");
1107 return;
1108 }
1109
1110 bool should_enter = true; //uc2
1111
1112 if (config_.enable_carma_streets_connection && entering_time > current_state.stamp.seconds()) //uc3
1113 should_enter = false;
1114
1115 if (isStateAllowedGreen(current_light_state_optional.get().second) && bool_optional_late_certainty.get() && should_enter) // if can make with certainty
1116 {
1117 transition_table_.signal(TransitEvent::RED_TO_GREEN_LIGHT); // If the light is green send the light transition
1118 // signal
1119 return;
1120 }
1121
1122 // A fixed buffer to add to stopping maneuvers once the vehicle is already stopped to ensure that they can have their
1123 // trajectory planned
1124 constexpr double stop_maneuver_buffer = 10.0;
1125
1126 // If the light is not green then continue waiting by creating a stop and wait maneuver on top of the vehicle
1128
1129 resp->new_plan.maneuvers.push_back(composeStopAndWaitManeuverMessage(
1130 current_state.downtrack - stop_maneuver_buffer, traffic_light_down_track, current_state.speed,
1131 current_state.lane_id, current_state.lane_id, rclcpp::Time(entering_time * 1e9),
1132 rclcpp::Time(entering_time * 1e9) + rclcpp::Duration::from_nanoseconds(config_.min_maneuver_planning_period * 1e9), stopping_accel));
1133}
1134
1135void LCIStrategicPlugin::planWhenDEPARTING(carma_planning_msgs::srv::PlanManeuvers::Request::SharedPtr req,
1136 carma_planning_msgs::srv::PlanManeuvers::Response::SharedPtr resp, const VehicleState& current_state,
1137 double intersection_end_downtrack, double intersection_speed_limit)
1138{
1140
1141 if (current_state.downtrack > intersection_end_downtrack)
1142 {
1143 transition_table_.signal(TransitEvent::INTERSECTION_EXIT); // If we are past the most recent
1144 return;
1145 }
1146
1147 // Calculate exit time assuming constant acceleration
1148 rclcpp::Time intersection_exit_time =
1149 current_state.stamp +
1150 rclcpp::Duration::from_nanoseconds(2.0 * (intersection_end_downtrack - current_state.downtrack) / (current_state.speed + intersection_speed_limit) * 1e9);
1151
1152 // Identify the lanelets which will be crossed by approach maneuvers lane follow maneuver
1153 std::vector<lanelet::ConstLanelet> crossed_lanelets =
1154 getLaneletsBetweenWithException(current_state.downtrack, intersection_end_downtrack, true, false);
1155
1156 // Compose intersection transit maneuver
1157 resp->new_plan.maneuvers.push_back(composeIntersectionTransitMessage(
1158 current_state.downtrack, intersection_end_downtrack, current_state.speed, intersection_speed_limit,
1159 current_state.stamp, intersection_exit_time, crossed_lanelets.back().id(), crossed_lanelets.back().id()));
1160}
1161
1163
1164void LCIStrategicPlugin::mobilityOperationCb(carma_v2x_msgs::msg::MobilityOperation::UniquePtr msg)
1165{
1166 if (msg->strategy == light_controlled_intersection_strategy_)
1167 {
1168 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Received Schedule message with id: " << msg->m_header.plan_id);
1170 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Approaching light Controlled Intersection: " << approaching_light_controlled_intersection_);
1171
1172 if (msg->m_header.recipient_id == config_.vehicle_id)
1173 {
1174 street_msg_timestamp_ = msg->m_header.timestamp;
1175 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "street_msg_timestamp_: " << street_msg_timestamp_);
1176 parseStrategyParams(msg->strategy_params);
1177 previous_strategy_params_ = msg->strategy_params;
1178 }
1179 }
1180
1181}
1182
1183void LCIStrategicPlugin::BSMCb(carma_v2x_msgs::msg::BSM::UniquePtr msg)
1184{
1185 std::vector<uint8_t> bsm_id_vec = msg->core_data.id;
1186 bsm_id_ = BSMHelper::BSMHelper::bsmIDtoString(bsm_id_vec);
1187 bsm_msg_count_ = msg->core_data.msg_count;
1188 bsm_sec_mark_ = msg->core_data.sec_mark;
1189}
1190
1191void LCIStrategicPlugin::parseStrategyParams(const std::string& strategy_params)
1192{
1193 // sample strategy_params: "et:1634067059"
1194 std::string params = strategy_params;
1195 std::vector<std::string> inputsParams;
1196 boost::algorithm::split(inputsParams, params, boost::is_any_of(","));
1197
1198 std::vector<std::string> et_parsed;
1199 boost::algorithm::split(et_parsed, inputsParams[0], boost::is_any_of(":"));
1200 auto new_scheduled_enter_time = std::stoull(et_parsed[1]);
1201
1202 if (scheduled_enter_time_ != new_scheduled_enter_time) //reset green buffer cache so it can be re-evaluated
1204
1205 scheduled_enter_time_ = new_scheduled_enter_time;
1206 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "scheduled_enter_time_: " << scheduled_enter_time_);
1207
1208}
1209
1210carma_v2x_msgs::msg::MobilityOperation LCIStrategicPlugin::generateMobilityOperation()
1211{
1212 carma_v2x_msgs::msg::MobilityOperation mo_;
1213 mo_.m_header.timestamp = now().nanoseconds()/1000000;
1214 mo_.m_header.sender_id = config_.vehicle_id;
1215 mo_.m_header.recipient_id = upcoming_id_;
1216 mo_.m_header.sender_bsm_id = bsm_id_;
1218
1219 double vehicle_acceleration_limit_ = config_.vehicle_accel_limit * config_.vehicle_accel_limit_multiplier;
1220 double vehicle_deceleration_limit_ = -1 * config_.vehicle_decel_limit * config_.vehicle_decel_limit_multiplier;
1221
1222 std::string intersection_turn_direction = "straight";
1223 if (intersection_turn_direction_ == TurnDirection::Right) intersection_turn_direction = "right";
1224 if (intersection_turn_direction_ == TurnDirection::Left) intersection_turn_direction = "left";
1225
1226 mo_.strategy_params = "access: 1, max_accel: " + std::to_string(vehicle_acceleration_limit_) + // NOTE: Access currently set to 1 at all times since its not specified by streets
1227 ", max_decel: " + std::to_string(vehicle_deceleration_limit_) + ", react_time: " + std::to_string(config_.reaction_time) +
1228 ", min_gap: " + std::to_string(config_.min_gap) + ", depart_pos: 0" + // NOTE: Departure position set to 0 at all times since it's not specified by streets
1229 ", turn_direction: " + intersection_turn_direction + ", msg_count: " + std::to_string(bsm_msg_count_) + ", sec_mark: " + std::to_string(bsm_sec_mark_);
1230
1231
1232 return mo_;
1233}
1234
1235TurnDirection LCIStrategicPlugin::getTurnDirectionAtIntersection(std::vector<lanelet::ConstLanelet> lanelets_list)
1236{
1237 TurnDirection turn_direction = TurnDirection::Straight;
1238 for (auto l:lanelets_list)
1239 {
1240 if(l.hasAttribute("turn_direction")) {
1241 std::string direction_attribute = l.attribute("turn_direction").value();
1242 if (direction_attribute == "right")
1243 {
1244 turn_direction = TurnDirection::Right;
1245 break;
1246 }
1247 else if (direction_attribute == "left")
1248 {
1249 turn_direction = TurnDirection::Left;
1250 break;
1251 }
1252 else turn_direction = TurnDirection::Straight;
1253 }
1254 else
1255 {
1256 // if there is no attribute, assumption is straight
1257 turn_direction = TurnDirection::Straight;
1258 }
1259
1260 }
1261 return turn_direction;
1262}
1263
1265{
1267 {
1268 carma_v2x_msgs::msg::MobilityOperation status_msg = generateMobilityOperation();
1269 mobility_operation_pub_->publish(status_msg);
1270 }
1271}
1272
1274
1276 std::shared_ptr<rmw_request_id_t> srv_header,
1277 carma_planning_msgs::srv::PlanManeuvers::Request::SharedPtr req,
1278 carma_planning_msgs::srv::PlanManeuvers::Response::SharedPtr resp)
1279{
1280 std::chrono::system_clock::time_point execution_start_time = std::chrono::system_clock::now(); // Start timing the execution time for planning so it can be logged
1281
1282 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "<<<<<<<<<<<<<<<<< STARTING LCI_STRATEGIC_PLAN!!!!!!!!! >>>>>>>>>>>>>>>>");
1283
1284 if (!wm_->getRoute())
1285 {
1286 RCLCPP_ERROR_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Could not plan maneuvers as route was not available");
1287 return;
1288 }
1289
1291 {
1293 {
1294 resp->new_plan.maneuvers = {};
1295 RCLCPP_WARN_STREAM(rclcpp::get_logger("lci_strategic_plugin"),"Not approaching light-controlled intersection so no maneuvers");
1296 return;
1297 }
1298
1299 bool is_empty_schedule_msg = (scheduled_enter_time_ == 0);
1300 if (is_empty_schedule_msg)
1301 {
1302 resp->new_plan.maneuvers = {};
1303 RCLCPP_WARN_STREAM(rclcpp::get_logger("lci_strategic_plugin"),"Receiving empty schedule message");
1304 return;
1305 }
1306 }
1307
1308 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Finding car information");
1309
1310 // Extract vehicle data from request
1311 VehicleState current_state = extractInitialState(req);
1312 if (transition_table_.getState() != TransitState::UNAVAILABLE && !req->prior_plan.maneuvers.empty())
1313 {
1314 RCLCPP_WARN_STREAM(rclcpp::get_logger("lci_strategic_plugin"),"State is NOT UNAVAILABLE AND Maneuvers in request is NOT empty");
1315 return;
1316 }
1317 // Get current traffic light information
1318 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "\n\nFinding traffic_light information");
1319
1320 auto inter_list = wm_->getSignalizedIntersectionsAlongRoute({ req->veh_x, req->veh_y });
1321 auto upcoming_id_= inter_list.front()->id();
1322
1323 auto traffic_list = wm_->getSignalsAlongRoute({ req->veh_x, req->veh_y });
1324
1325 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Found traffic lights of size: " << traffic_list.size());
1326
1327 auto current_lanelets = wm_->getLaneletsFromPoint({ req->veh_x, req->veh_y});
1328 lanelet::ConstLanelet current_lanelet;
1329
1330 if (current_lanelets.empty())
1331 {
1332 RCLCPP_ERROR_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Given vehicle position is not on the road! Returning...");
1333 return;
1334 }
1335
1336 // get the lanelet that is on the route in case overlapping ones found
1337 auto llt_on_route_optional = wm_->getFirstLaneletOnShortestPath(current_lanelets);
1338
1339 if (llt_on_route_optional){
1340 current_lanelet = llt_on_route_optional.value();
1341 }
1342 else{
1343 RCLCPP_WARN_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "When identifying the corresponding lanelet for requested maneuever's state, x: "
1344 << req->veh_x << ", y: " << req->veh_y << ", no possible lanelet was found to be on the shortest path."
1345 << "Picking arbitrary lanelet: " << current_lanelets[0].id() << ", instead");
1346 current_lanelet = current_lanelets[0];
1347 }
1348
1349 lanelet::CarmaTrafficSignalPtr nearest_traffic_signal = nullptr;
1350
1351 lanelet::ConstLanelet entry_lanelet;
1352 lanelet::ConstLanelet exit_lanelet;
1353
1354 for (auto signal : traffic_list)
1355 {
1356 auto optional_entry_exit = wm_->getEntryExitOfSignalAlongRoute(signal);
1357 // if signal is not matching our destination skip
1358 if (!optional_entry_exit)
1359 {
1360 RCLCPP_ERROR_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Did not find entry.exit along the route");
1361 continue;
1362 }
1363
1364 entry_lanelet = optional_entry_exit.get().first;
1365 exit_lanelet = optional_entry_exit.get().second;
1366
1367 nearest_traffic_signal = signal;
1368 break;
1369 }
1370
1371
1372 TransitState prev_state;
1373
1374 do
1375 {
1376 // Clear previous maneuvers planned by this plugin as guard against state change since each state generates an
1377 // independent set of maneuvers
1378 resp->new_plan = carma_planning_msgs::msg::ManeuverPlan();
1379
1380 prev_state = transition_table_.getState(); // Cache previous state to check if state has changed after 1 iteration
1381
1382 RCLCPP_INFO_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Planning in state: " << transition_table_.getState());
1383
1384 boost::optional<std::pair<boost::posix_time::ptime, lanelet::CarmaTrafficSignalState>> current_light_state_optional = boost::none;
1385 if (nearest_traffic_signal)
1386 {
1387 current_light_state_optional = nearest_traffic_signal->predictState(lanelet::time::timeFromSec(current_state.stamp.seconds()));
1388 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Real-time current signal: " << current_light_state_optional.get().second << ", for Id: " << nearest_traffic_signal->id());
1389 if (current_light_state_optional.get().second == lanelet::CarmaTrafficSignalState::UNAVAILABLE || !current_light_state_optional)
1390 {
1391 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Signal state not available returning..." );
1392 return;
1393 }
1394 }
1395 switch (transition_table_.getState())
1396 {
1398 planWhenUNAVAILABLE(req, resp, current_state, nearest_traffic_signal, entry_lanelet, exit_lanelet, current_lanelet);
1399 break;
1400
1402 planWhenAPPROACHING(req, resp, current_state, nearest_traffic_signal, entry_lanelet, exit_lanelet, current_lanelet);
1403 break;
1404
1406 planWhenWAITING(req, resp, current_state, nearest_traffic_signal, entry_lanelet, exit_lanelet, current_lanelet);
1407 break;
1408
1410 // Reset intersection state since we are no longer in an intersection
1412 {
1413 throw std::invalid_argument("State is DEPARTING but the intersection variables are not available");
1414 }
1415 planWhenDEPARTING(req, resp, current_state, intersection_end_downtrack_.get(), intersection_speed_.get());
1416 break;
1417
1418 default:
1419 throw std::invalid_argument("LCIStrategic Strategic Plugin entered unknown state");
1420 break;
1421 }
1422
1423 } while (transition_table_.getState() != prev_state); // If the state has changed then continue looping
1424
1425 std::chrono::system_clock::time_point execution_end_time = std::chrono::system_clock::now(); // Planning complete
1426
1427 auto execution_duration = execution_end_time - execution_start_time;
1428 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "ExecutionTime lci_strategic_plugin: " << std::chrono::duration<double>(execution_duration).count());
1429
1430 return;
1431 // We need to evaluate the events so the state transitions can be triggered
1432}
1433
1434carma_planning_msgs::msg::Maneuver LCIStrategicPlugin::composeTrajectorySmoothingManeuverMessage(double start_dist, double end_dist, const std::vector<lanelet::ConstLanelet>& crossed_lanelets, double start_speed,
1435 double target_speed, rclcpp::Time start_time, rclcpp::Time end_time,
1436 const TrajectoryParams& tsp) const
1437{
1438 carma_planning_msgs::msg::Maneuver maneuver_msg;
1439 maneuver_msg.type = carma_planning_msgs::msg::Maneuver::LANE_FOLLOWING;
1440 maneuver_msg.lane_following_maneuver.parameters.negotiation_type =
1441 carma_planning_msgs::msg::ManeuverParameters::NO_NEGOTIATION;
1442 maneuver_msg.lane_following_maneuver.parameters.presence_vector =
1443 carma_planning_msgs::msg::ManeuverParameters::HAS_TACTICAL_PLUGIN | carma_planning_msgs::msg::ManeuverParameters::HAS_FLOAT_META_DATA | carma_planning_msgs::msg::ManeuverParameters::HAS_INT_META_DATA;
1444 maneuver_msg.lane_following_maneuver.parameters.planning_tactical_plugin =
1446 maneuver_msg.lane_following_maneuver.parameters.planning_strategic_plugin =
1448 maneuver_msg.lane_following_maneuver.start_dist = start_dist;
1449 maneuver_msg.lane_following_maneuver.start_speed = start_speed;
1450 maneuver_msg.lane_following_maneuver.start_time = start_time;
1451 maneuver_msg.lane_following_maneuver.end_dist = end_dist;
1452 maneuver_msg.lane_following_maneuver.end_speed = target_speed;
1453 maneuver_msg.lane_following_maneuver.end_time = end_time;
1454
1455 maneuver_msg.lane_following_maneuver.parameters.string_valued_meta_data.push_back(light_controlled_intersection_strategy_);
1456
1457 maneuver_msg.lane_following_maneuver.parameters.float_valued_meta_data.push_back(tsp.a1_);
1458 maneuver_msg.lane_following_maneuver.parameters.float_valued_meta_data.push_back(tsp.v1_);
1459 maneuver_msg.lane_following_maneuver.parameters.float_valued_meta_data.push_back(tsp.x1_);
1460
1461 maneuver_msg.lane_following_maneuver.parameters.float_valued_meta_data.push_back(tsp.a2_);
1462 maneuver_msg.lane_following_maneuver.parameters.float_valued_meta_data.push_back(tsp.v2_);
1463 maneuver_msg.lane_following_maneuver.parameters.float_valued_meta_data.push_back(tsp.x2_);
1464
1465 maneuver_msg.lane_following_maneuver.parameters.float_valued_meta_data.push_back(tsp.a3_);
1466 maneuver_msg.lane_following_maneuver.parameters.float_valued_meta_data.push_back(tsp.v3_);
1467 maneuver_msg.lane_following_maneuver.parameters.float_valued_meta_data.push_back(tsp.x3_);
1468
1469 maneuver_msg.lane_following_maneuver.parameters.int_valued_meta_data.push_back(static_cast<int>(tsp.case_num));
1470 maneuver_msg.lane_following_maneuver.parameters.int_valued_meta_data.push_back(static_cast<int>(tsp.is_algorithm_successful));
1471
1472 for (auto llt : crossed_lanelets)
1473 {
1474 maneuver_msg.lane_following_maneuver.lane_ids.push_back(std::to_string(llt.id()));
1475 }
1476 // Start time and end time for maneuver are assigned in updateTimeProgress
1477
1478 RCLCPP_INFO_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Creating TrajectorySmoothingManeuver start dist: " << start_dist << " end dist: " << end_dist
1479 << " start_time: " << std::to_string(start_time.seconds())
1480 << " end_time: " << std::to_string(end_time.seconds()));
1481
1482 return maneuver_msg;
1483}
1484
1485carma_planning_msgs::msg::Maneuver LCIStrategicPlugin::composeStopAndWaitManeuverMessage(double current_dist, double end_dist,
1486 double start_speed,
1487 const lanelet::Id& starting_lane_id,
1488 const lanelet::Id& ending_lane_id,
1489 rclcpp::Time start_time, rclcpp::Time end_time, double stopping_accel) const
1490{
1491 carma_planning_msgs::msg::Maneuver maneuver_msg;
1492 maneuver_msg.type = carma_planning_msgs::msg::Maneuver::STOP_AND_WAIT;
1493 maneuver_msg.stop_and_wait_maneuver.parameters.negotiation_type = carma_planning_msgs::msg::ManeuverParameters::NO_NEGOTIATION;
1494 maneuver_msg.stop_and_wait_maneuver.parameters.presence_vector =
1495 carma_planning_msgs::msg::ManeuverParameters::HAS_TACTICAL_PLUGIN | carma_planning_msgs::msg::ManeuverParameters::HAS_FLOAT_META_DATA;
1496 maneuver_msg.stop_and_wait_maneuver.parameters.planning_tactical_plugin = config_.stop_and_wait_plugin_name;
1497 maneuver_msg.stop_and_wait_maneuver.parameters.planning_strategic_plugin = config_.strategic_plugin_name;
1498 maneuver_msg.stop_and_wait_maneuver.start_dist = current_dist;
1499 maneuver_msg.stop_and_wait_maneuver.end_dist = end_dist;
1500 maneuver_msg.stop_and_wait_maneuver.start_speed = start_speed;
1501 maneuver_msg.stop_and_wait_maneuver.start_time = start_time;
1502 maneuver_msg.stop_and_wait_maneuver.end_time = end_time;
1503 maneuver_msg.stop_and_wait_maneuver.starting_lane_id = std::to_string(starting_lane_id);
1504 maneuver_msg.stop_and_wait_maneuver.ending_lane_id = std::to_string(ending_lane_id);
1505
1506 // Set the meta data for the stop location buffer
1507 maneuver_msg.stop_and_wait_maneuver.parameters.float_valued_meta_data.push_back(config_.stopping_location_buffer);
1508 maneuver_msg.stop_and_wait_maneuver.parameters.float_valued_meta_data.push_back(stopping_accel);
1509
1510 RCLCPP_INFO_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Creating stop and wait start dist: " << current_dist << " end dist: " << end_dist
1511 << " start_time: " << std::to_string(start_time.seconds())
1512 << " end_time: " << std::to_string(end_time.seconds())
1513 << " stopping_accel: " << stopping_accel);
1514
1515 return maneuver_msg;
1516}
1517
1518carma_planning_msgs::msg::Maneuver LCIStrategicPlugin::composeIntersectionTransitMessage(double start_dist, double end_dist,
1519 double start_speed, double target_speed,
1520 rclcpp::Time start_time, rclcpp::Time end_time,
1521 const lanelet::Id& starting_lane_id,
1522 const lanelet::Id& ending_lane_id) const
1523{
1524 carma_planning_msgs::msg::Maneuver maneuver_msg;
1525 maneuver_msg.type = carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_STRAIGHT;
1526 maneuver_msg.intersection_transit_straight_maneuver.parameters.negotiation_type =
1527 carma_planning_msgs::msg::ManeuverParameters::NO_NEGOTIATION;
1528 maneuver_msg.intersection_transit_straight_maneuver.parameters.presence_vector =
1529 carma_planning_msgs::msg::ManeuverParameters::HAS_TACTICAL_PLUGIN;
1530 maneuver_msg.intersection_transit_straight_maneuver.parameters.planning_tactical_plugin =
1532 maneuver_msg.intersection_transit_straight_maneuver.parameters.planning_strategic_plugin =
1534 maneuver_msg.intersection_transit_straight_maneuver.start_dist = start_dist;
1535 maneuver_msg.intersection_transit_straight_maneuver.start_speed = start_speed;
1536 maneuver_msg.intersection_transit_straight_maneuver.start_time = start_time;
1537 maneuver_msg.intersection_transit_straight_maneuver.end_dist = end_dist;
1538 maneuver_msg.intersection_transit_straight_maneuver.end_speed = target_speed;
1539 maneuver_msg.intersection_transit_straight_maneuver.end_time = end_time;
1540 maneuver_msg.intersection_transit_straight_maneuver.starting_lane_id = std::to_string(starting_lane_id);
1541 maneuver_msg.intersection_transit_straight_maneuver.ending_lane_id = std::to_string(ending_lane_id);
1542
1543 // Start time and end time for maneuver are assigned in updateTimeProgress
1544
1545 RCLCPP_INFO_STREAM(rclcpp::get_logger("lci_strategic_plugin"), "Creating IntersectionTransitManeuver start dist: " << start_dist << " end dist: " << end_dist
1546 << " From lanelet: " << starting_lane_id
1547 << " to lanelet: " << ending_lane_id
1548 << " From start_time: " << std::to_string(start_time.seconds())
1549 << " to end_time: " << std::to_string(end_time.seconds()));
1550
1551 return maneuver_msg;
1552}
1553
1555{
1556 return true;
1557}
1558
1560{
1561 return "v1.0";
1562}
1563
1564} // namespace lci_strategic_plugin
1565
1566
1567#include "rclcpp_components/register_node_macro.hpp"
1568
1569// Register the component with class_loader
1570RCLCPP_COMPONENTS_REGISTER_NODE(lci_strategic_plugin::LCIStrategicPlugin)
virtual carma_wm::WorldModelConstPtr get_world_model() final
Method to return the default world model provided as a convience by this base class If this method or...
virtual std::shared_ptr< carma_wm::WMListener > get_world_model_listener() final
Method to return the default world model listener provided as a convience by this base class If this ...
void handleStopping(carma_planning_msgs::srv::PlanManeuvers::Request::SharedPtr req, carma_planning_msgs::srv::PlanManeuvers::Response::SharedPtr resp, const VehicleState &current_state, const lanelet::CarmaTrafficSignalPtr &traffic_light, const lanelet::ConstLanelet &entry_lanelet, const lanelet::ConstLanelet &exit_lanelet, const lanelet::ConstLanelet &current_lanelet, double traffic_light_down_track, bool is_emergency=false)
This function returns stopping maneuver if the vehicle is able to stop at red and in safe stopping di...
void handleGreenSignalScenario(carma_planning_msgs::srv::PlanManeuvers::Request::SharedPtr req, carma_planning_msgs::srv::PlanManeuvers::Response::SharedPtr resp, const VehicleState &current_state, double current_state_speed, const lanelet::CarmaTrafficSignalPtr &traffic_light, const lanelet::ConstLanelet &entry_lanelet, const lanelet::ConstLanelet &exit_lanelet, double traffic_light_down_track, const TrajectoryParams &ts_params, bool is_certainty_check_optional)
This function returns valid maneuvers if the vehicle is able to utilize trajectory smoothing paramete...
void lookupFrontBumperTransform()
Lookup transfrom from front bumper to base link.
LCIStrategicPluginConfig config_
Config containing configurable algorithm parameters.
boost::optional< bool > canArriveAtGreenWithCertainty(const rclcpp::Time &light_arrival_time_by_algo, const lanelet::CarmaTrafficSignalPtr &traffic_light, bool check_late, bool check_early) const
Return true if the car can arrive at given arrival time within green light time buffer.
BoundaryDistances get_delta_x(double v0, double v1, double v_max, double v_min, double a_max, double a_min)
Get boundary distances used to compare against current state in order to create trajectory smoothing ...
carma_ros2_utils::CallbackReturn on_activate_plugin()
Method which is triggered when this plugin is moved from the INACTIVE to ACTIVE states....
bool validLightState(const boost::optional< std::pair< boost::posix_time::ptime, lanelet::CarmaTrafficSignalState > > &optional_state, const rclcpp::Time &source_time) const
Helper method that checks both if the input optional light state is set and if the state it contains ...
TrajectoryParams handleFailureCaseHelper(const lanelet::CarmaTrafficSignalPtr &traffic_light, double current_time, double starting_speed, double departure_speed, double speed_limit, double remaining_downtrack, double traffic_light_downtrack)
Helper function to handleFailureCase that modifies ts_params to desired new parameters....
VehicleState extractInitialState(carma_planning_msgs::srv::PlanManeuvers::Request::SharedPtr req) const
Helper method to extract the initial vehicle state from the planning request method based on if the p...
boost::optional< rclcpp::Time > nearest_green_entry_time_cached_
carma_wm::WorldModelConstPtr wm_
World Model pointer.
void mobilityOperationCb(carma_v2x_msgs::msg::MobilityOperation::UniquePtr msg)
callback function for mobility operation
carma_ros2_utils::PubPtr< std_msgs::msg::Float64 > tf_distance_pub_
double findSpeedLimit(const lanelet::ConstLanelet &llt) const
Given a Lanelet, find it's associated Speed Limit.
carma_planning_msgs::msg::Maneuver composeTrajectorySmoothingManeuverMessage(double start_dist, double end_dist, const std::vector< lanelet::ConstLanelet > &crossed_lanelets, double start_speed, double target_speed, rclcpp::Time start_time, rclcpp::Time end_time, const TrajectoryParams &tsp) const
Compose a trajectory smoothing maneuver msg (sent as transit maneuver message)
rclcpp::Duration get_earliest_entry_time(double remaining_distance, double free_flow_speed, double current_speed, double departure_speed, double max_accel, double max_decel) const
Gets the earliest entry time into the intersection that is kinematically possible for the vehicle....
void planWhenDEPARTING(carma_planning_msgs::srv::PlanManeuvers::Request::SharedPtr req, carma_planning_msgs::srv::PlanManeuvers::Response::SharedPtr resp, const VehicleState &current_state, double intersection_end_downtrack, double intersection_speed_limit)
Method for performing maneuver planning when the current plugin state is TransitState::DEPARTING Ther...
carma_ros2_utils::SubPtr< carma_v2x_msgs::msg::MobilityOperation > mob_operation_sub_
carma_ros2_utils::CallbackReturn on_configure_plugin()
Method which is triggered when this plugin is moved from the UNCONFIGURED to INACTIVE states....
carma_ros2_utils::SubPtr< carma_v2x_msgs::msg::BSM > bsm_sub_
carma_ros2_utils::PubPtr< std_msgs::msg::Int8 > case_pub_
bool get_availability()
Get the availability status of this plugin based on the current operating environment....
void handleFailureCase(carma_planning_msgs::srv::PlanManeuvers::Request::SharedPtr req, carma_planning_msgs::srv::PlanManeuvers::Response::SharedPtr resp, const VehicleState &current_state, double current_state_speed, double speed_limit, double remaining_time, lanelet::Id exit_lanelet_id, const lanelet::CarmaTrafficSignalPtr &traffic_light, double traffic_light_down_track, const TrajectoryParams &ts_params)
When the vehicle is not able to successfully run the algorithm or not able to stop,...
std::tuple< rclcpp::Time, bool, bool > get_final_entry_time_and_conditions(const VehicleState &current_state, const rclcpp::Time &earliest_entry_time, lanelet::CarmaTrafficSignalPtr traffic_light)
Get the final entry time from either vehicle's own internal ET calculation (TSMO UC2) or from carma-s...
LCIStrategicPlugin(const rclcpp::NodeOptions &)
Default constructor for RouteFollowingPlugin class.
std::vector< lanelet::ConstLanelet > getLaneletsBetweenWithException(double start_downtrack, double end_downtrack, bool shortest_path_only=false, bool bounds_inclusive=true) const
Helper method which calls carma_wm::WorldModel::getLaneletsBetween(start_downtrack,...
void planWhenWAITING(carma_planning_msgs::srv::PlanManeuvers::Request::SharedPtr req, carma_planning_msgs::srv::PlanManeuvers::Response::SharedPtr resp, const VehicleState &current_state, const lanelet::CarmaTrafficSignalPtr &traffic_light, const lanelet::ConstLanelet &entry_lanelet, const lanelet::ConstLanelet &exit_lanelet, const lanelet::ConstLanelet &current_lanelet)
Method for performing maneuver planning when the current plugin state is TransitState::WAITING Theref...
void BSMCb(carma_v2x_msgs::msg::BSM::UniquePtr msg)
BSM callback function.
void print_params(TrajectoryParams params)
Helper method to print TrajectoryParams.
void parseStrategyParams(const std::string &strategy_params)
parse strategy parameters
carma_v2x_msgs::msg::MobilityOperation generateMobilityOperation()
Generates Mobility Operation messages.
carma_ros2_utils::PubPtr< std_msgs::msg::Float64 > earliest_et_pub_
TrajectoryParams get_ts_case(double t, double et, double v0, double v1, double v_max, double v_min, double a_max, double a_min, double x0, double x_end, double dx, BoundaryDistances boundary_distances, std::vector< TrajectoryParams > params)
std::shared_ptr< tf2_ros::Buffer > tf2_buffer_
void planWhenUNAVAILABLE(carma_planning_msgs::srv::PlanManeuvers::Request::SharedPtr req, carma_planning_msgs::srv::PlanManeuvers::Response::SharedPtr resp, const VehicleState &current_state, const lanelet::CarmaTrafficSignalPtr &traffic_light, const lanelet::ConstLanelet &entry_lanelet, const lanelet::ConstLanelet &exit_lanelet, const lanelet::ConstLanelet &current_lanelet)
Method for performing maneuver planning when the current plugin state is TransitState::UNAVAILABLE Th...
void publishTrajectorySmoothingInfo()
Publish trajectory smoothing info at a fixed rate.
carma_ros2_utils::PubPtr< carma_v2x_msgs::msg::MobilityOperation > mobility_operation_pub_
carma_planning_msgs::msg::Maneuver composeStopAndWaitManeuverMessage(double current_dist, double end_dist, double start_speed, const lanelet::Id &starting_lane_id, const lanelet::Id &ending_lane_id, rclcpp::Time start_time, rclcpp::Time end_time, double stopping_accel) const
Compose a stop and wait maneuver message based on input params.
std::string get_version_id()
Returns the version id of this plugin.
void handleCruisingUntilStop(carma_planning_msgs::srv::PlanManeuvers::Request::SharedPtr req, carma_planning_msgs::srv::PlanManeuvers::Response::SharedPtr resp, const VehicleState &current_state, double current_state_speed, const lanelet::CarmaTrafficSignalPtr &traffic_light, double traffic_light_down_track, const TrajectoryParams &ts_params)
This function returns valid maneuvers if the vehicle is able to utilize trajectory smoothing paramete...
boost::optional< double > intersection_end_downtrack_
double estimate_distance_to_stop(double v, double a) const
Helper method to use basic kinematics to compute an estimated stopping distance from from the inputs.
bool isStateAllowedGreen(const lanelet::CarmaTrafficSignalState &state) const
Method to check if the state is an allowed green movement state. Currently Permissive and Protected g...
TurnDirection getTurnDirectionAtIntersection(std::vector< lanelet::ConstLanelet > lanelets_list)
Determine the turn direction at intersection.
void plan_maneuvers_callback(std::shared_ptr< rmw_request_id_t > srv_header, carma_planning_msgs::srv::PlanManeuvers::Request::SharedPtr req, carma_planning_msgs::srv::PlanManeuvers::Response::SharedPtr resp)
Service callback for arbitrator maneuver planning.
void planWhenAPPROACHING(carma_planning_msgs::srv::PlanManeuvers::Request::SharedPtr req, carma_planning_msgs::srv::PlanManeuvers::Response::SharedPtr resp, const VehicleState &current_state, const lanelet::CarmaTrafficSignalPtr &traffic_light, const lanelet::ConstLanelet &entry_lanelet, const lanelet::ConstLanelet &exit_lanelet, const lanelet::ConstLanelet &current_lanelet)
Method for performing maneuver planning when the current plugin state is TransitState::APPROACHING Th...
LCIStrategicStateTransitionTable transition_table_
State Machine Transition table.
std::vector< TrajectoryParams > get_boundary_traj_params(double t, double v0, double v1, double v_max, double v_min, double a_max, double a_min, double x0, double x_end, double dx, BoundaryDistances boundary_distances)
Get all possible trajectory smoothing parameters for each segments. Later this will be used to genera...
TSCase last_case_num_
Useful metrics for LCI Plugin.
void print_boundary_distances(BoundaryDistances delta_xs)
Helper method to print TrajectoryParams.
std::shared_ptr< tf2_ros::TransformListener > tf2_listener_
boost::optional< double > intersection_speed_
Cache variables for storing the current intersection state between state machine transitions.
void publishMobilityOperation()
Publish mobility operation at a fixed rate.
rcl_interfaces::msg::SetParametersResult parameter_update_callback(const std::vector< rclcpp::Parameter > &parameters)
Callback for dynamic parameter updates.
bool supportedLightState(lanelet::CarmaTrafficSignalState state) const
Helper method to evaluate if the given traffic light state is supported by this plugin.
rclcpp::TimerBase::SharedPtr ts_info_pub_timer_
carma_ros2_utils::PubPtr< std_msgs::msg::Float64 > et_pub_
rclcpp::TimerBase::SharedPtr mob_op_pub_timer_
carma_planning_msgs::msg::Maneuver composeIntersectionTransitMessage(double start_dist, double end_dist, double start_speed, double target_speed, rclcpp::Time start_time, rclcpp::Time end_time, const lanelet::Id &starting_lane_id, const lanelet::Id &ending_lane_id) const
Compose a intersection transit maneuver message based on input params.
TransitState getState() const
Returns the current state.
void signal(TransitEvent signal)
Trigger signal for the transition table.
#define EPSILON
#define GET_MANEUVER_PROPERTY(mvr, property)
auto to_string(const UtmZone &zone) -> std::string
Definition: utm_zone.cpp:21
TransitState
Enum describing the possible states of the LCIStrategic Strategic Plugin.
Definition: lci_states.hpp:25
Struct to store the configuration settings for the LCIStrategicPlugin class.
bool enable_carma_streets_connection
Bool: Enable carma streets connection.
std::string vehicle_id
License plate of the vehicle.
double trajectory_smoothing_activation_distance
Downtrack distance until nearest intersection where the Trajectory Smoothing algorithm should activat...
double algo_minimum_speed
Minimum allowable speed TS algorithm in m/s.
double vehicle_accel_limit_multiplier
A multiplier to apply to the maximum allowable vehicle acceleration limit so we plan under our capabi...
double min_maneuver_planning_period
The minimum period in seconds which a maneuver plan must cover if the plugin wishes to control the wh...
double green_light_time_buffer
A buffer in seconds around the green phase which will reduce the phase length such that vehicle still...
std::string stop_and_wait_plugin_name
The name of the plugin to use for stop and wait trajectory planning.
double stopping_location_buffer
A buffer infront of the stopping location which will still be considered a valid stop....
double reaction_time
Double: Vehicle reaction time to a received schedule in seconds (approximate value,...
double vehicle_decel_limit
The maximum allowable vehicle deceleration limit in m/s.
double vehicle_decel_limit_multiplier
A multiplier to apply to the maximum allowable vehicle deceleration limit so we plan under our capabi...
double min_approach_distance
The minimum distance in meters that the vehicle can be at before requiring a transition to the APPROA...
int enable_carma_wm_spat_processing
Int: 0 to turn off and 1 to turn on.
double vehicle_accel_limit
The maximum allowable vehicle acceleration limit in m/s.
std::string strategic_plugin_name
The name to use for this plugin during comminications with the arbitrator.
double mobility_rate
Double: Mobility operation rate.
double desired_distance_to_stop_buffer
Double: Desired distance to stop buffer in meters.
double min_gap
Double: Minimum inter-vehicle gap.
Struct representing a vehicle state for the purposes of planning.