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.
sci_strategic_plugin.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2022 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 */
17
18#define GET_MANEUVER_PROPERTY(mvr, property) \
19 (((mvr).type == carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_LEFT_TURN ? \
20 (mvr).intersection_transit_left_turn_maneuver.property : \
21 ((mvr).type == carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_RIGHT_TURN ? \
22 (mvr).intersection_transit_right_turn_maneuver.property : \
23 ((mvr).type == carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_STRAIGHT ? \
24 (mvr).intersection_transit_straight_maneuver.property : \
25 ((mvr).type == carma_planning_msgs::msg::Maneuver::LANE_CHANGE ? (mvr).lane_change_maneuver.property : \
26 ((mvr).type == carma_planning_msgs::msg::Maneuver::LANE_FOLLOWING ? (mvr).lane_following_maneuver.property : \
27 ((mvr).type == carma_planning_msgs::msg::Maneuver::STOP_AND_WAIT ? (mvr).stop_and_wait_maneuver.property : \
28 throw new std::invalid_argument("GET_MANEUVER_" \
29 "PROPERTY " \
30 "(property) " \
31 "called on " \
32 "maneuver with " \
33 "invalid type " \
34 "id"))))))))
35
36
38{
39namespace std_ph = std::placeholders;
40
41namespace {
47 double getManeuverEndSpeed(const carma_planning_msgs::msg::Maneuver& mvr)
48 {
49 switch(mvr.type)
50 {
51 case carma_planning_msgs::msg::Maneuver::LANE_FOLLOWING:
52 return mvr.lane_following_maneuver.end_speed;
53 case carma_planning_msgs::msg::Maneuver::LANE_CHANGE:
54 return mvr.lane_change_maneuver.end_speed;
55 case carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_STRAIGHT:
56 return mvr.intersection_transit_straight_maneuver.end_speed;
57 case carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_LEFT_TURN:
58 return mvr.intersection_transit_left_turn_maneuver.end_speed;
59 case carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_RIGHT_TURN:
60 return mvr.intersection_transit_right_turn_maneuver.end_speed;
61 case carma_planning_msgs::msg::Maneuver::STOP_AND_WAIT:
62 return 0;
63 default:
64 RCLCPP_ERROR_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Requested end speed from unsupported maneuver type");
65 return 0;
66 }
67 }
68} // namespace anonymous
69
70SCIStrategicPlugin::SCIStrategicPlugin(const rclcpp::NodeOptions &options)
71 : carma_guidance_plugins::StrategicPlugin(options), config_(SCIStrategicPluginConfig())
72{
73 // Declare parameters
74 config_.vehicle_decel_limit_multiplier = declare_parameter<double>("vehicle_decel_limit_multiplier", config_.vehicle_decel_limit_multiplier);
75 config_.vehicle_accel_limit_multiplier = declare_parameter<double>("vehicle_accel_limit_multiplier", config_.vehicle_accel_limit_multiplier);
76 config_.stop_line_buffer = declare_parameter<double>("stop_line_buffer", config_.stop_line_buffer);
77 config_.delta_t = declare_parameter<double>("delta_t", config_.delta_t);
78 config_.min_gap = declare_parameter<double>("min_gap", config_.min_gap);
79 config_.reaction_time = declare_parameter<double>("reaction_time", config_.reaction_time);
80 config_.intersection_exit_zone_length = declare_parameter<double>("intersection_exit_zone_length", config_.intersection_exit_zone_length);
81 config_.strategic_plugin_name = declare_parameter<std::string>("strategic_plugin_name", config_.strategic_plugin_name);
82 config_.lane_following_plugin_name = declare_parameter<std::string>("lane_following_plugin_name", config_.lane_following_plugin_name);
83 config_.intersection_transit_plugin_name = declare_parameter<std::string>("intersection_transit_plugin_name", config_.intersection_transit_plugin_name);
84 config_.vehicle_id = declare_parameter<std::string>("vehicle_id", config_.vehicle_id);
85 config_.veh_length = declare_parameter<double>("vehicle_length", config_.veh_length);
86 config_.vehicle_decel_limit = declare_parameter<double>("vehicle_deceleration_limit", config_.vehicle_decel_limit);
87 config_.vehicle_accel_limit = declare_parameter<double>("vehicle_acceleration_limit", config_.vehicle_accel_limit);
88
89};
90
91carma_ros2_utils::CallbackReturn SCIStrategicPlugin::on_configure_plugin()
92{
93 // reset config
95 // Declare parameters
96 get_parameter<double>("vehicle_decel_limit_multiplier", config_.vehicle_decel_limit_multiplier);
97 get_parameter<double>("vehicle_accel_limit_multiplier", config_.vehicle_accel_limit_multiplier);
98 get_parameter<double>("stop_line_buffer", config_.stop_line_buffer);
99 get_parameter<double>("delta_t", config_.delta_t);
100 get_parameter<double>("min_gap", config_.min_gap);
101 get_parameter<double>("reaction_time", config_.reaction_time);
102 get_parameter<double>("intersection_exit_zone_length", config_.intersection_exit_zone_length);
103 get_parameter<std::string>("strategic_plugin_name", config_.strategic_plugin_name);
104 get_parameter<std::string>("lane_following_plugin_name", config_.lane_following_plugin_name);
105 get_parameter<std::string>("intersection_transit_plugin_name", config_.intersection_transit_plugin_name);
106 get_parameter<std::string>("vehicle_id", config_.vehicle_id);
107 get_parameter<double>("vehicle_length", config_.veh_length);
108 get_parameter<double>("vehicle_deceleration_limit", config_.vehicle_decel_limit);
109 get_parameter<double>("vehicle_acceleration_limit", config_.vehicle_accel_limit);
110
111 // Register runtime parameter update callback
112 add_on_set_parameters_callback(std::bind(&SCIStrategicPlugin::parameter_update_callback, this, std_ph::_1));
113
114 RCLCPP_INFO_STREAM(rclcpp::get_logger("sci_strategic_plugin"),"Done loading parameters: " << config_);
115
116 // Mobility Operation Subscriber
117 mob_operation_sub_ = create_subscription<carma_v2x_msgs::msg::MobilityOperation>("incoming_mobility_operation", 1,
118 std::bind(&SCIStrategicPlugin::mobilityOperationCb,this,std_ph::_1));
119
120 // Current Pose Subscriber
121 current_pose_sub_ = create_subscription<geometry_msgs::msg::PoseStamped>("current_pose", 1,
122 std::bind(&SCIStrategicPlugin::currentPoseCb,this,std_ph::_1));
123
124 // BSM subscriber
125 bsm_sub_ = create_subscription<carma_v2x_msgs::msg::BSM>("bsm_outbound", 1,
126 std::bind(&SCIStrategicPlugin::BSMCb,this,std_ph::_1));
127
128 // Guidance State subscriber
129 guidance_state_sub_ = create_subscription<carma_planning_msgs::msg::GuidanceState>("guidance_state", 5,
130 std::bind(&SCIStrategicPlugin::guidance_state_cb, this, std::placeholders::_1));
131
132 // set world model point form wm listener
134
135 // Setup publishers
136 mobility_operation_pub_ = create_publisher<carma_v2x_msgs::msg::MobilityOperation>("outgoing_mobility_operation", 1);
137
138 // Return success if everthing initialized successfully
139 return CallbackReturn::SUCCESS;
140}
141
142rcl_interfaces::msg::SetParametersResult SCIStrategicPlugin::parameter_update_callback(const std::vector<rclcpp::Parameter> &parameters)
143{
144 auto error_double = update_params<double>({
145 {"vehicle_decel_limit_multiplier", config_.vehicle_decel_limit_multiplier},
146 {"vehicle_accel_limit_multiplier", config_.vehicle_accel_limit_multiplier},
147 {"stop_line_buffer", config_.stop_line_buffer},
148 {"delta_t", config_.delta_t},
149 {"min_gap", config_.min_gap},
150 {"reaction_time", config_.reaction_time},
151 {"intersection_exit_zone_length", config_.intersection_exit_zone_length}
152 }, parameters); // vehicle_acceleration_limit not updated as it's global param
153
154 rcl_interfaces::msg::SetParametersResult result;
155
156 result.successful = !error_double;
157
158 return result;
159}
160
161carma_ros2_utils::CallbackReturn SCIStrategicPlugin::on_activate_plugin()
162{
163 mob_op_pub_timer_ = create_timer(get_clock(),
164 std::chrono::duration<double>(0.1),
166
167 return CallbackReturn::SUCCESS;
168}
169
170SCIStrategicPlugin::VehicleState SCIStrategicPlugin::extractInitialState(const carma_planning_msgs::srv::PlanManeuvers::Request& req) const
171{
172 VehicleState state;
173 if (!req.prior_plan.maneuvers.empty())
174 {
175 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Provided with initial plan...");
176 state.stamp = GET_MANEUVER_PROPERTY(req.prior_plan.maneuvers.back(), end_time);
177 state.speed = getManeuverEndSpeed(req.prior_plan.maneuvers.back());
178 state.downtrack = GET_MANEUVER_PROPERTY(req.prior_plan.maneuvers.back(), end_dist);
179 state.lane_id = getLaneletsBetweenWithException(state.downtrack, state.downtrack, true).front().id();
180 }
181 else
182 {
183 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "No initial plan provided...");
184
185 state.stamp = req.header.stamp;
186 state.downtrack = req.veh_downtrack;
187 state.speed = req.veh_logitudinal_velocity;
188 state.lane_id = stoi(req.veh_lane_id);
189 }
190
191 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "state.stamp: " << std::to_string(state.stamp.seconds()));
192 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "state.downtrack : " << state.downtrack );
193 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "state.speed: " << state.speed);
194 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "state.lane_id: " << state.lane_id);
195
196 return state;
197}
198
199void SCIStrategicPlugin::mobilityOperationCb(carma_v2x_msgs::msg::MobilityOperation::UniquePtr msg)
200{
201 if (msg->strategy == stop_controlled_intersection_strategy_)
202 {
203 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Received Schedule message with id: " << msg->m_header.plan_id);
205 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Approaching Stop Controlled Intersection: " << approaching_stop_controlled_interction_);
206
207 if (msg->m_header.recipient_id == config_.vehicle_id)
208 {
209 street_msg_timestamp_ = msg->m_header.timestamp;
210 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "street_msg_timestamp_: " << street_msg_timestamp_);
211 parseStrategyParams(msg->strategy_params);
212 }
213 previous_strategy_params_ = msg->strategy_params;
214 }
215
216}
217
218void SCIStrategicPlugin::BSMCb(carma_v2x_msgs::msg::BSM::UniquePtr msg)
219{
220 std::vector<uint8_t> bsm_id_vec = msg->core_data.id;
221 bsm_id_ = BSMHelper::BSMHelper::bsmIDtoString(bsm_id_vec);
222 bsm_msg_count_ = msg->core_data.msg_count;
223 bsm_sec_mark_ = msg->core_data.sec_mark;
224}
225
226void SCIStrategicPlugin::guidance_state_cb(const carma_planning_msgs::msg::GuidanceState::UniquePtr msg)
227{
229}
230
231void SCIStrategicPlugin::currentPoseCb(geometry_msgs::msg::PoseStamped::UniquePtr msg)
232{
233 geometry_msgs::msg::PoseStamped pose_msg = geometry_msgs::msg::PoseStamped(*msg.get());
235 {
236 lanelet::BasicPoint2d current_loc(pose_msg.pose.position.x, pose_msg.pose.position.y);
237 current_downtrack_ = wm_->routeTrackPos(current_loc).downtrack;
238 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Downtrack from current pose: " << current_downtrack_);
239 }
240
241
242}
243
244void SCIStrategicPlugin::parseStrategyParams(const std::string& strategy_params)
245{
246 // sample strategy_params: "st:1634067044,et:1634067059, dt:1634067062.3256602,dp:2,,access: 0"
247 std::string params = strategy_params;
248 std::vector<std::string> inputsParams;
249 boost::algorithm::split(inputsParams, params, boost::is_any_of(","));
250
251 std::vector<std::string> st_parsed;
252 boost::algorithm::split(st_parsed, inputsParams[0], boost::is_any_of(":"));
253 scheduled_stop_time_ = std::stoull(st_parsed[1]);
254 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "scheduled_stop_time_: " << scheduled_stop_time_);
255
256 std::vector<std::string> et_parsed;
257 boost::algorithm::split(et_parsed, inputsParams[1], boost::is_any_of(":"));
258 scheduled_enter_time_ = std::stoull(et_parsed[1]);
259 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "scheduled_enter_time_: " << scheduled_enter_time_);
260
261 std::vector<std::string> dt_parsed;
262 boost::algorithm::split(dt_parsed, inputsParams[2], boost::is_any_of(":"));
263 scheduled_depart_time_ = std::stoull(dt_parsed[1]);
264 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "scheduled_depart_time_: " << scheduled_depart_time_);
265
266
267 std::vector<std::string> dp_parsed;
268 boost::algorithm::split(dp_parsed, inputsParams[3], boost::is_any_of(":"));
269 scheduled_departure_position_ = std::stoi(dp_parsed[1]);
270 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "scheduled_departure_position_: " << scheduled_departure_position_);
271
272 std::vector<std::string> access_parsed;
273 boost::algorithm::split(access_parsed, inputsParams[4], boost::is_any_of(":"));
274 int access = std::stoi(access_parsed[1]);
275 is_allowed_int_ = (access == 1);
276 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "is_allowed_int_: " << is_allowed_int_);
277
278}
279
280int SCIStrategicPlugin::determine_speed_profile_case(double stop_dist, double current_speed, double schedule_stop_time, double speed_limit)
281{
282 int case_num = 0;
283 double estimated_stop_time = calcEstimatedStopTime(stop_dist, current_speed);
284
285 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "estimated_stop_time: " << estimated_stop_time);
286 if (estimated_stop_time < schedule_stop_time)
287 {
288 case_num = 3;
289 }
290 else
291 {
292 double speed_before_stop = calc_speed_before_decel(estimated_stop_time, stop_dist, current_speed);
293 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "speed_before_stop: " << speed_before_stop);
294 if (speed_before_stop < speed_limit)
295 {
296 case_num = 1;
297 }
298 else
299 {
300 case_num = 2;
301 }
302 }
303
304 return case_num;
305}
306
307double SCIStrategicPlugin::calcEstimatedStopTime(double stop_dist, double current_speed) const
308{
309
310 double t_stop = 0;
311 t_stop = 2*stop_dist/current_speed;
312 return t_stop;
313}
314
315double SCIStrategicPlugin::calc_speed_before_decel(double stop_time, double stop_dist, double current_speed) const
316{
317 double speed_before_decel = 0;
318
320 double desired_deceleration = -1 * config_.vehicle_decel_limit * config_.vehicle_decel_limit_multiplier;
321
322 double sqr_term = sqrt(pow(1 - (desired_acceleration/desired_deceleration), 2) * pow(stop_dist/stop_time, 2)
323 + (1 - (desired_acceleration/desired_deceleration))*(current_speed*current_speed - 2*current_speed*stop_dist/stop_time));
324
325 speed_before_decel = (stop_dist/stop_time) + sqr_term/(1 - (desired_acceleration/desired_deceleration));
326
327 return speed_before_decel;
328}
329
330
331std::vector<lanelet::ConstLanelet> SCIStrategicPlugin::getLaneletsBetweenWithException(double start_downtrack,
332 double end_downtrack,
333 bool shortest_path_only,
334 bool bounds_inclusive) const
335{
336 std::vector<lanelet::ConstLanelet> crossed_lanelets =
337 wm_->getLaneletsBetween(start_downtrack, end_downtrack, shortest_path_only, bounds_inclusive);
338
339 if (crossed_lanelets.empty())
340 {
341 throw std::invalid_argument("getLaneletsBetweenWithException called but inputs do not cross any lanelets going "
342 "from: " +
343 std::to_string(start_downtrack) + " to: " + std::to_string(end_downtrack));
344 }
345
346 return crossed_lanelets;
347}
348
349
350
352 std::shared_ptr<rmw_request_id_t> srv_header,
353 carma_planning_msgs::srv::PlanManeuvers::Request::SharedPtr req,
354 carma_planning_msgs::srv::PlanManeuvers::Response::SharedPtr resp)
355{
356 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "In Maneuver callback...");
357 vehicle_engaged_ = true;
358
359 if (!wm_->getRoute())
360 {
361 RCLCPP_ERROR_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Could not plan maneuvers as route was not available");
362 return;
363 }
364
366 {
367 resp->new_plan.maneuvers = {};
368 RCLCPP_WARN_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Not approaching stop-controlled intersection so no maneuvers");
369 return;
370 }
371
372 bool is_empty_schedule_msg = (scheduled_depart_time_ == 0 && scheduled_stop_time_ == 0 && scheduled_enter_time_ == 0);
373 if (is_empty_schedule_msg)
374 {
375 resp->new_plan.maneuvers = {};
376 RCLCPP_WARN_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Receiving empty schedule message");
377 return;
378 }
379
380 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Planning for intersection...");
381
382 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Finding car information");
383 // Extract vehicle data from request
384 VehicleState current_state = extractInitialState(*req);
385
386 // Get current traffic light information
387 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "\n\nFinding intersection information");
388
389 auto stop_intersection_list = wm_->getIntersectionsAlongRoute({ req->veh_x, req->veh_y });
390 bool no_intersections = stop_intersection_list.empty();
391 if (no_intersections)
392 {
393 resp->new_plan.maneuvers = {};
394 RCLCPP_WARN_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "There are no stop controlled intersections in the map");
395 return;
396 }
397
398 auto nearest_stop_intersection = stop_intersection_list.front();
399
400 bool no_stop_lines = nearest_stop_intersection->stopLines().empty();
401 if (no_stop_lines)
402 {
403 resp->new_plan.maneuvers = {};
404 RCLCPP_WARN_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "There are no stop lines on the closest stop-controlled intersections in the map");
405 return;
406 }
407
408
409 // extract the intersection stop line information
410 std::vector<double> stop_lines;
411 for (auto l : nearest_stop_intersection->stopLines())
412 {
413 //TODO: temp use veh_length here until planning stack is updated with front bumper pos
414 double stop_bar_dtd = wm_->routeTrackPos(l.front().basicPoint2d()).downtrack - config_.veh_length;
415 stop_lines.push_back(stop_bar_dtd);
416 }
417 std::sort(stop_lines.begin(), stop_lines.end());
418
419 double stop_intersection_down_track = stop_lines.front();
420
421 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "stop_intersection_down_track " << stop_intersection_down_track);
422
423
424 double distance_to_stopline = stop_intersection_down_track - current_downtrack_ - config_.stop_line_buffer;
425 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "distance_to_stopline " << distance_to_stopline);
426
427 if (distance_to_stopline < -config_.intersection_exit_zone_length)
428 {
429 resp->new_plan.maneuvers = {};
430 RCLCPP_WARN_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Already passed intersection, sending empty maneuvers");
431 return;
432 }
433
434
435 double intersection_end_downtrack = stop_lines.back();
436 // Identify the lanelets of the intersection
437 std::vector<lanelet::ConstLanelet> intersection_lanelets =
438 getLaneletsBetweenWithException(stop_intersection_down_track, intersection_end_downtrack, true, true);
439
440 // find the turn direction at intersection:
441
443
444 uint32_t base_time = street_msg_timestamp_;
445
446 bool time_to_approach_int = int((scheduled_stop_time_) - (street_msg_timestamp_))>0;
447 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "time_to_approach_int " << time_to_approach_int);
448
449 carma_planning_msgs::msg::Maneuver maneuver_planned;
450
451
452 if (time_to_approach_int)
453 {
455 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "tmp " << tmp);
456 double time_to_schedule_stop = (tmp)/1000.0;
457 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "time_to_schedule_stop " << time_to_schedule_stop);
458 // Identify the lanelets which will be crossed by approach maneuvers lane follow maneuver
459 std::vector<lanelet::ConstLanelet> crossed_lanelets =
460 getLaneletsBetweenWithException(current_downtrack_, stop_intersection_down_track, true, true);
461
462 // approaching stop line
463 speed_limit_ = findSpeedLimit(crossed_lanelets.front());
464
465 // lane following to intersection
466
467 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "time_to_schedule_stop " << time_to_schedule_stop);
468
470
471
472 double safe_distance = pow(current_state.speed, 2)/(2*desired_deceleration);
473 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "safe_distance: " << safe_distance);
474
475 if (distance_to_stopline - safe_distance > config_.stop_line_buffer)
476 {
477 int case_num = determine_speed_profile_case(distance_to_stopline , current_state.speed, time_to_schedule_stop, speed_limit_);
478 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "case_num: " << case_num);
479
480 if (case_num < 3)
481 {
482 maneuver_planned = composeLaneFollowingManeuverMessage(
483 case_num, current_state.downtrack, stop_intersection_down_track, current_state.speed, 0.0,
484 current_state.stamp, time_to_schedule_stop,
485 lanelet::utils::transform(crossed_lanelets, [](const auto& ll) { return ll.id(); }));
486 resp->new_plan.maneuvers.push_back(maneuver_planned);
487 }
488 else
489 {
490 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Decelerating to stop at the intersection");
491
492 // at the stop line or decelerating to stop line
493 // stop and wait maneuver
494
495 std::vector<lanelet::ConstLanelet> crossed_lanelets =
496 getLaneletsBetweenWithException(current_downtrack_, stop_intersection_down_track, true, true);
497
498
499 double stopping_accel = caseThreeSpeedProfile(distance_to_stopline, current_state.speed, time_to_schedule_stop);
500 stopping_accel = std::max(-stopping_accel, desired_deceleration);
501 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "used deceleration for case three: " << stopping_accel);
502
503 maneuver_planned = composeStopAndWaitManeuverMessage(
504 current_state.downtrack, stop_intersection_down_track, current_state.speed, crossed_lanelets[0].id(),
505 crossed_lanelets[0].id(), stopping_accel, current_state.stamp,
506 current_state.stamp + rclcpp::Duration(time_to_schedule_stop*1e9));
507
508 resp->new_plan.maneuvers.push_back(maneuver_planned);
509
510 }
511 }
512 else
513 {
514 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Too close to the intersection, constant deceleration to stop");
515
516 maneuver_planned = composeStopAndWaitManeuverMessage(
517 current_state.downtrack, stop_intersection_down_track, current_state.speed, crossed_lanelets[0].id(),
518 crossed_lanelets[0].id(), desired_deceleration, current_state.stamp,
519 current_state.stamp + rclcpp::Duration(time_to_schedule_stop*1e9));
520 }
521 }
522
523 bool time_to_reach_stopline = int((street_msg_timestamp_) - (scheduled_stop_time_)) >= 0;
524 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "time_to_reach_stopline: " << time_to_reach_stopline);
525 bool not_time_to_intersection_traverse = int((street_msg_timestamp_) - (scheduled_enter_time_)) < 0;
526 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "not_time_to_intersection_traverse: " << not_time_to_intersection_traverse);
527 bool time_to_stop_at_stopline = (time_to_reach_stopline && not_time_to_intersection_traverse);
528 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "time_to_stop_at_stopline: " << time_to_stop_at_stopline);
529
530 if (time_to_stop_at_stopline)
531 {
532 base_time = std::max(scheduled_stop_time_, street_msg_timestamp_);
533 double stop_duration = int(scheduled_enter_time_ - base_time)/1000;
534 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "stop_duration: " << stop_duration);
535 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Planning stop and wait maneuver");
537 auto stop_line_lanelet = nearest_stop_intersection->lanelets().front();
538
539 maneuver_planned = composeStopAndWaitManeuverMessage(
540 current_state.downtrack, stop_intersection_down_track, current_state.speed, stop_line_lanelet.id(),
541 stop_line_lanelet.id(), stopping_accel, current_state.stamp,
542 current_state.stamp + rclcpp::Duration(stop_duration*1e9));
543 }
544
545 if (!is_allowed_int_)
546 {
547 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Vehicle at stop line, waiting for access to intersection");
548 // vehicle is at the intersection but it is not allowed access, so it must wait
549 // arbitrary parameters
551 double stop_duration = 999;//std::numeric_limits<double>::max();
552
553 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "current_downtrack_: " << current_downtrack_);
554 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "current state dtd: " << current_state.downtrack);
555 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "stop_intersection_down_track dtd: " << stop_intersection_down_track);
556
557 maneuver_planned = composeStopAndWaitManeuverMessage(
558 current_state.downtrack, stop_intersection_down_track, current_state.speed, current_state.lane_id,
559 current_state.lane_id, stop_acc, current_state.stamp,
560 current_state.stamp + rclcpp::Duration(stop_duration*1e9));
561
562 }
563
564 bool time_for_crossing = int((street_msg_timestamp_) - (scheduled_enter_time_)) >= 0;
565 // time to cross intersection
566
567 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "time for crossing? " << time_for_crossing);
568
569 if (time_for_crossing && is_allowed_int_)
570 {
571 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "street_msg_timestamp_ - scheduled_enter_time_ = " << street_msg_timestamp_ - scheduled_enter_time_);
572
573
574 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Vehicle is crossing the intersection");
575 // Passing the stop line
576
577 // Compose intersection transit maneuver
578 base_time = std::max(scheduled_enter_time_, street_msg_timestamp_);
579 double intersection_transit_time = (scheduled_depart_time_ - base_time)/1000;
580 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "intersection_transit_time: " << intersection_transit_time);
581
582 intersection_transit_time = config_.min_maneuver_planning_period;//std::max(intersection_transit_time, config_.min_maneuver_planning_period);
583 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "used intersection_transit_time: " << intersection_transit_time);
584 // Identify the lanelets which will be crossed by approach maneuvers lane follow maneuver
585 std::vector<lanelet::ConstLanelet> crossed_lanelets =
586 getLaneletsBetweenWithException(current_downtrack_, intersection_end_downtrack, true, true);
587
588
589 // find the turn direction at intersection:
590
592
593 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "turn direction at the intersection is: " << intersection_turn_direction_);
594
595 double intersection_speed_limit = findSpeedLimit(nearest_stop_intersection->lanelets().front());
596
597 // when passing intersection, set the flag to false
598 double end_of_intersection = std::max(config_.intersection_exit_zone_length, intersection_end_downtrack - stop_intersection_down_track);
599 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Actual length of intersection: " << intersection_end_downtrack - stop_intersection_down_track);
600 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Used length of intersection: " << end_of_intersection);
601
602 maneuver_planned = composeIntersectionTransitMessage(
603 current_state.downtrack, current_state.downtrack + end_of_intersection, current_state.speed, intersection_speed_limit,
604 current_state.stamp, rclcpp::Time(req->header.stamp) + rclcpp::Duration(intersection_transit_time*1e9), intersection_turn_direction_, crossed_lanelets.front().id(), crossed_lanelets.back().id());
605
606
607 if (distance_to_stopline < -end_of_intersection)
608 {
609 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Vehicle is out of intersection, stop planning...");
610 // once the vehicle crosses the intersection, reset the flag to stop planning and publishing status/intent
612 // once the intersection is crossed, reset turn direction
614 }
615
616 }
617 resp->new_plan.maneuvers.push_back(maneuver_planned);
618
619 return;
620}
621
622TurnDirection SCIStrategicPlugin::getTurnDirectionAtIntersection(std::vector<lanelet::ConstLanelet> lanelets_list)
623{
624 TurnDirection turn_direction = TurnDirection::Straight;
625 for (auto l:lanelets_list)
626 {
627 if(l.hasAttribute("turn_direction")) {
628 std::string direction_attribute = l.attribute("turn_direction").value();
629 if (direction_attribute == "right")
630 {
631 turn_direction = TurnDirection::Right;
632 break;
633 }
634 else if (direction_attribute == "left")
635 {
636 turn_direction = TurnDirection::Left;
637 break;
638 }
639 else turn_direction = TurnDirection::Straight;
640 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "intersection crossed lanelet direction is: " << turn_direction);
641 }
642 else
643 {
644 // if there is no attribute, assumption is straight
645 turn_direction = TurnDirection::Straight;
646 }
647
648 }
649 return turn_direction;
650}
651
652void SCIStrategicPlugin::caseOneSpeedProfile(double speed_before_decel, double current_speed, double stop_time,
653 std::vector<double>* float_metadata_list) const
654{
656 double desired_deceleration = -1 * config_.vehicle_decel_limit * config_.vehicle_decel_limit_multiplier;
657
658 // Equations obtained from TSMO UC 1 Algorithm draft doc
659 double a_acc = ((1 - desired_acceleration/desired_deceleration)*speed_before_decel - current_speed)/stop_time;
660 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Case one a_acc: " << a_acc);
661 a_acc = std::min(a_acc, desired_acceleration);
662 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Used Case one a_acc: " << a_acc);
663
664 double a_dec = ((desired_deceleration - desired_acceleration)*speed_before_decel - desired_deceleration * current_speed)/(desired_acceleration * stop_time);
665 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Case one a_dec: " << a_dec);
666 a_dec = std::max(a_dec, desired_deceleration);
667 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Used Case one a_dec: " << a_dec);
668
669 double t_acc = (speed_before_decel - current_speed)/a_acc;
670 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Case one t_acc: " << t_acc);
671 double t_dec = -speed_before_decel/a_dec; // a_dec is negative so a - is used to make the t_dec positive.
672 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Case one t_dec: " << t_dec);
673 float_metadata_list->push_back(a_acc);
674 float_metadata_list->push_back(a_dec);
675 float_metadata_list->push_back(t_acc);
676 float_metadata_list->push_back(t_dec);
677 float_metadata_list->push_back(speed_before_decel);
678}
679
680void SCIStrategicPlugin::caseTwoSpeedProfile(double stop_dist, double speed_before_decel,
681 double current_speed, double stop_time, double speed_limit,
682 std::vector<double>* float_metadata_list) const
683{
685 double desired_deceleration = -1 * config_.vehicle_decel_limit * config_.vehicle_decel_limit_multiplier;
686
687 if (speed_before_decel > speed_limit)
688 {
689 speed_before_decel = speed_limit;
690 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Case two speed_before_decel: " << speed_before_decel);
691 }
692
693 double t_c_nom = 2*stop_dist * ((1 - desired_acceleration/desired_deceleration)*speed_limit - current_speed) -
694 stop_time * ((1 - desired_acceleration/desired_deceleration)*pow(speed_limit,2) - pow(current_speed, 2));
695 double t_c_den = pow(speed_limit - current_speed, 2) - (desired_acceleration/desired_deceleration) * pow(speed_limit, 2);
696 double t_cruise = t_c_nom / t_c_den;
697 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Case two t_cruise: " << t_cruise);
698
699 // Equations obtained from TSMO UC 1 Algorithm draft doc
700 double a_acc = ((1 - desired_acceleration/desired_deceleration)*speed_limit - current_speed)/(stop_time - t_cruise);
701 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Case two a_acc: " << a_acc);
702 a_acc = std::min(desired_acceleration, std::abs(a_acc));
703 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Used Case two a_acc: " << a_acc);
704
705 double a_dec = ((desired_deceleration - desired_acceleration)*speed_limit - desired_deceleration * current_speed)/(desired_acceleration*(stop_time - t_cruise));
706 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Case two a_dec: " << a_dec);
707 a_dec = -1*std::min(desired_deceleration, std::abs(a_dec));
708 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Used Case two a_dec: " << a_dec);
709
710 double t_acc = (speed_limit - current_speed)/a_acc;
711 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Case two t_acc: " << t_acc);
712 double t_dec = -speed_limit/a_dec; // a_dec is negative so a - is used to make the t_dec positive.
713 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Case two t_dec: " << t_dec);
714
715 float_metadata_list->push_back(a_acc);
716 float_metadata_list->push_back(a_dec);
717 float_metadata_list->push_back(t_acc);
718 float_metadata_list->push_back(t_dec);
719 float_metadata_list->push_back(t_cruise);
720 float_metadata_list->push_back(speed_before_decel);
721
722}
723
724double SCIStrategicPlugin::caseThreeSpeedProfile(double stop_dist, double current_speed, double stop_time) const
725{
726 double a_dec = (2*stop_dist - current_speed*(stop_time + config_.delta_t))/(stop_time * config_.delta_t);
727 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Case three a_dec: " << a_dec);
728 return a_dec;
729}
730
731carma_planning_msgs::msg::Maneuver SCIStrategicPlugin::composeLaneFollowingManeuverMessage(int case_num, double start_dist, double end_dist,
732 double start_speed, double target_speed,
733 rclcpp::Time start_time, double time_to_stop,
734 std::vector<lanelet::Id> lane_ids)
735{
736 carma_planning_msgs::msg::Maneuver maneuver_msg;
737 carma_planning_msgs::msg::Maneuver empty_msg;
738 maneuver_msg.type = carma_planning_msgs::msg::Maneuver::LANE_FOLLOWING;
739 maneuver_msg.lane_following_maneuver.parameters.planning_strategic_plugin = config_.strategic_plugin_name;
740 maneuver_msg.lane_following_maneuver.parameters.presence_vector =
741 carma_planning_msgs::msg::ManeuverParameters::HAS_TACTICAL_PLUGIN | carma_planning_msgs::msg::ManeuverParameters::HAS_INT_META_DATA |
742 carma_planning_msgs::msg::ManeuverParameters::HAS_FLOAT_META_DATA | carma_planning_msgs::msg::ManeuverParameters::HAS_STRING_META_DATA;
743 maneuver_msg.lane_following_maneuver.parameters.negotiation_type = carma_planning_msgs::msg::ManeuverParameters::NO_NEGOTIATION;
744 maneuver_msg.lane_following_maneuver.parameters.planning_tactical_plugin = config_.lane_following_plugin_name;
745 maneuver_msg.lane_following_maneuver.start_dist = start_dist;
746 maneuver_msg.lane_following_maneuver.end_dist = end_dist;
747 maneuver_msg.lane_following_maneuver.start_speed = start_speed;
748 maneuver_msg.lane_following_maneuver.end_speed = target_speed;
749 maneuver_msg.lane_following_maneuver.start_time = start_time;
750 maneuver_msg.lane_following_maneuver.end_time = start_time + rclcpp::Duration(time_to_stop*1e9);
751 maneuver_msg.lane_following_maneuver.lane_ids =
752 lanelet::utils::transform(lane_ids, [](auto id) { return std::to_string(id); });
753
754 RCLCPP_INFO_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Creating lane follow start dist: " << start_dist << " end dist: " << end_dist);
755
756 std::vector<double> float_metadata_list;
757
758 double speed_before_decel = calc_speed_before_decel(time_to_stop, end_dist-start_dist, start_speed);
759
760 switch(case_num)
761 {
762 case 1:
763 caseOneSpeedProfile(speed_before_decel, start_speed, time_to_stop, &float_metadata_list);
764 break;
765 case 2:
766 caseTwoSpeedProfile(end_dist-start_dist, speed_before_decel, start_speed, time_to_stop, speed_limit_, &float_metadata_list);
767 break;
768 default:
769 return empty_msg;
770 }
771
772
773 maneuver_msg.lane_following_maneuver.parameters.int_valued_meta_data.push_back(case_num);
774 maneuver_msg.lane_following_maneuver.parameters.string_valued_meta_data.push_back(stop_controlled_intersection_strategy_);
775 maneuver_msg.lane_following_maneuver.parameters.float_valued_meta_data = float_metadata_list;
776
777 return maneuver_msg;
778}
779
780
781double SCIStrategicPlugin::findSpeedLimit(const lanelet::ConstLanelet& llt) const
782{
783 lanelet::Optional<carma_wm::TrafficRulesConstPtr> traffic_rules = wm_->getTrafficRules();
784 if (traffic_rules)
785 {
786 return (*traffic_rules)->speedLimit(llt).speedLimit.value();
787 }
788 else
789 {
790 throw std::invalid_argument("Valid traffic rules object could not be built");
791 }
792}
793
794carma_v2x_msgs::msg::MobilityOperation SCIStrategicPlugin::generateMobilityOperation()
795{
796 carma_v2x_msgs::msg::MobilityOperation mo_;
797 mo_.m_header.timestamp = now().nanoseconds()/1000000;
798 mo_.m_header.sender_id = config_.vehicle_id;
799 mo_.m_header.sender_bsm_id = bsm_id_;
801
802 double vehicle_acceleration_limit_ = config_.vehicle_accel_limit * config_.vehicle_accel_limit_multiplier;
803 double vehicle_deceleration_limit_ = -1 * config_.vehicle_decel_limit * config_.vehicle_decel_limit_multiplier;
804
805 std::string intersection_turn_direction = "straight";
806 if (intersection_turn_direction_ == TurnDirection::Right) intersection_turn_direction = "right";
807 if (intersection_turn_direction_ == TurnDirection::Left) intersection_turn_direction = "left";
808
809
810 mo_.strategy_params = "access: " + std::to_string(is_allowed_int_) + ", max_accel: " + std::to_string(vehicle_acceleration_limit_) +
811 ", max_decel: " + std::to_string(vehicle_deceleration_limit_) + ", react_time: " + std::to_string(config_.reaction_time) +
812 ", min_gap: " + std::to_string(config_.min_gap) + ", depart_pos: " + std::to_string(scheduled_departure_position_) +
813 ", turn_direction: " + intersection_turn_direction + ", msg_count: " + std::to_string(bsm_msg_count_) + ", sec_mark: " + std::to_string(bsm_sec_mark_);
814
815
816 return mo_;
817}
818
820{
822 {
823 carma_v2x_msgs::msg::MobilityOperation status_msg = generateMobilityOperation();
824 mobility_operation_pub_->publish(status_msg);
825 }
826}
827
828
829carma_planning_msgs::msg::Maneuver SCIStrategicPlugin::composeStopAndWaitManeuverMessage(double current_dist, double end_dist,
830 double start_speed,
831 const lanelet::Id& starting_lane_id,
832 const lanelet::Id& ending_lane_id, double stopping_accel,
833 rclcpp::Time start_time, rclcpp::Time end_time) const
834{
835 carma_planning_msgs::msg::Maneuver maneuver_msg;
836 maneuver_msg.type = carma_planning_msgs::msg::Maneuver::STOP_AND_WAIT;
837 maneuver_msg.stop_and_wait_maneuver.parameters.planning_strategic_plugin = config_.strategic_plugin_name;
838 maneuver_msg.stop_and_wait_maneuver.parameters.presence_vector =
839 carma_planning_msgs::msg::ManeuverParameters::HAS_TACTICAL_PLUGIN | carma_planning_msgs::msg::ManeuverParameters::HAS_FLOAT_META_DATA;
840 maneuver_msg.stop_and_wait_maneuver.parameters.negotiation_type = carma_planning_msgs::msg::ManeuverParameters::NO_NEGOTIATION;
841 maneuver_msg.stop_and_wait_maneuver.parameters.planning_tactical_plugin = config_.stop_and_wait_plugin_name;
842 maneuver_msg.stop_and_wait_maneuver.start_speed = start_speed;
843 maneuver_msg.stop_and_wait_maneuver.start_dist = current_dist;
844 maneuver_msg.stop_and_wait_maneuver.end_dist = end_dist;
845 maneuver_msg.stop_and_wait_maneuver.start_time = start_time;
846 maneuver_msg.stop_and_wait_maneuver.end_time = end_time;
847 maneuver_msg.stop_and_wait_maneuver.starting_lane_id = std::to_string(starting_lane_id);
848 maneuver_msg.stop_and_wait_maneuver.ending_lane_id = std::to_string(ending_lane_id);
849 // Set the meta data for the stop location buffer
850 maneuver_msg.stop_and_wait_maneuver.parameters.float_valued_meta_data.push_back(config_.stop_line_buffer);
851 maneuver_msg.stop_and_wait_maneuver.parameters.float_valued_meta_data.push_back(stopping_accel);
852
853 RCLCPP_INFO_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Creating stop and wait start dist: " << current_dist << " end dist: " << end_dist);
854
855 return maneuver_msg;
856}
857
858carma_planning_msgs::msg::Maneuver SCIStrategicPlugin::composeIntersectionTransitMessage(double start_dist, double end_dist,
859 double start_speed, double target_speed,
860 rclcpp::Time start_time, rclcpp::Time end_time,
861 TurnDirection turn_direction,
862 const lanelet::Id& starting_lane_id,
863 const lanelet::Id& ending_lane_id) const
864{
865 carma_planning_msgs::msg::Maneuver maneuver_msg;
866 if (turn_direction == TurnDirection::Left)
867 {
868 maneuver_msg.type = carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_LEFT_TURN;
869 maneuver_msg.intersection_transit_left_turn_maneuver.parameters.planning_strategic_plugin =
871 maneuver_msg.intersection_transit_left_turn_maneuver.parameters.planning_tactical_plugin =
873 maneuver_msg.intersection_transit_left_turn_maneuver.parameters.presence_vector =
874 carma_planning_msgs::msg::ManeuverParameters::HAS_TACTICAL_PLUGIN;
875 maneuver_msg.intersection_transit_left_turn_maneuver.parameters.negotiation_type =
876 carma_planning_msgs::msg::ManeuverParameters::NO_NEGOTIATION;
877 maneuver_msg.intersection_transit_left_turn_maneuver.start_dist = start_dist;
878 maneuver_msg.intersection_transit_left_turn_maneuver.end_dist = end_dist;
879 maneuver_msg.intersection_transit_left_turn_maneuver.start_speed = start_speed;
880 maneuver_msg.intersection_transit_left_turn_maneuver.end_speed = target_speed;
881 maneuver_msg.intersection_transit_left_turn_maneuver.start_time = start_time;
882 maneuver_msg.intersection_transit_left_turn_maneuver.end_time = end_time;
883 maneuver_msg.intersection_transit_left_turn_maneuver.starting_lane_id = std::to_string(starting_lane_id);
884 maneuver_msg.intersection_transit_left_turn_maneuver.ending_lane_id = std::to_string(ending_lane_id);
885
886 }
887 else if (turn_direction == TurnDirection::Right)
888 {
889 maneuver_msg.type = carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_RIGHT_TURN;
890 maneuver_msg.intersection_transit_right_turn_maneuver.parameters.planning_strategic_plugin =
892 maneuver_msg.intersection_transit_right_turn_maneuver.parameters.planning_tactical_plugin =
894 maneuver_msg.intersection_transit_right_turn_maneuver.parameters.presence_vector =
895 carma_planning_msgs::msg::ManeuverParameters::HAS_TACTICAL_PLUGIN;
896 maneuver_msg.intersection_transit_right_turn_maneuver.parameters.negotiation_type =
897 carma_planning_msgs::msg::ManeuverParameters::NO_NEGOTIATION;
898 maneuver_msg.intersection_transit_right_turn_maneuver.start_dist = start_dist;
899 maneuver_msg.intersection_transit_right_turn_maneuver.end_dist = end_dist;
900 maneuver_msg.intersection_transit_right_turn_maneuver.start_speed = start_speed;
901 maneuver_msg.intersection_transit_right_turn_maneuver.end_speed = target_speed;
902 maneuver_msg.intersection_transit_right_turn_maneuver.start_time = start_time;
903 maneuver_msg.intersection_transit_right_turn_maneuver.end_time = end_time;
904 maneuver_msg.intersection_transit_right_turn_maneuver.starting_lane_id = std::to_string(starting_lane_id);
905 maneuver_msg.intersection_transit_right_turn_maneuver.ending_lane_id = std::to_string(ending_lane_id);
906
907 }
908 else
909 {
910 maneuver_msg.type = carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_STRAIGHT;
911 maneuver_msg.intersection_transit_straight_maneuver.parameters.planning_strategic_plugin =
913 maneuver_msg.intersection_transit_straight_maneuver.parameters.planning_tactical_plugin =
915 maneuver_msg.intersection_transit_straight_maneuver.parameters.presence_vector =
916 carma_planning_msgs::msg::ManeuverParameters::HAS_TACTICAL_PLUGIN;
917 maneuver_msg.intersection_transit_straight_maneuver.parameters.negotiation_type =
918 carma_planning_msgs::msg::ManeuverParameters::NO_NEGOTIATION;
919 maneuver_msg.intersection_transit_straight_maneuver.start_dist = start_dist;
920 maneuver_msg.intersection_transit_straight_maneuver.end_dist = end_dist;
921 maneuver_msg.intersection_transit_straight_maneuver.start_speed = start_speed;
922 maneuver_msg.intersection_transit_straight_maneuver.end_speed = target_speed;
923 maneuver_msg.intersection_transit_straight_maneuver.start_time = start_time;
924 maneuver_msg.intersection_transit_straight_maneuver.end_time = end_time;
925 maneuver_msg.intersection_transit_straight_maneuver.starting_lane_id = std::to_string(starting_lane_id);
926 maneuver_msg.intersection_transit_straight_maneuver.ending_lane_id = std::to_string(ending_lane_id);
927
928 }
929
930
931
932 // Start time and end time for maneuver are assigned in updateTimeProgress
933
934 RCLCPP_INFO_STREAM(rclcpp::get_logger("sci_strategic_plugin"), "Creating IntersectionTransitManeuver start dist: " << start_dist << " end dist: " << end_dist
935 << " From lanelet: " << starting_lane_id
936 << " to lanelet: " << ending_lane_id);
937
938 return maneuver_msg;
939}
940
942{
943 return true;
944}
945
947{
948 return "v1.0";
949}
950
951} // namespace SCI_strategic_plugin
952
953#include "rclcpp_components/register_node_macro.hpp"
954
955// Register the component with class_loader
956RCLCPP_COMPONENTS_REGISTER_NODE(sci_strategic_plugin::SCIStrategicPlugin)
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...
carma_wm::WorldModelConstPtr wm_
World Model pointer.
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,...
double calcEstimatedStopTime(double stop_dist, double current_speed) const
calculate the time vehicle will stop with optimal decelarion
void guidance_state_cb(const carma_planning_msgs::msg::GuidanceState::UniquePtr msg)
Callback for the Guidance State.
int determine_speed_profile_case(double stop_dist, double current_speed, double schedule_stop_time, double speed_limit)
Determine the speed profile case fpr approaching an intersection.
carma_ros2_utils::SubPtr< geometry_msgs::msg::PoseStamped > current_pose_sub_
VehicleState extractInitialState(const carma_planning_msgs::srv::PlanManeuvers::Request &req) const
Helper method to extract the initial vehicle state from the planning request method based on if the p...
void parseStrategyParams(const std::string &strategy_params)
parse strategy parameters
void BSMCb(carma_v2x_msgs::msg::BSM::UniquePtr msg)
BSM callback function.
TurnDirection getTurnDirectionAtIntersection(std::vector< lanelet::ConstLanelet > lanelets_list)
Determine the turn direction at intersection.
rcl_interfaces::msg::SetParametersResult parameter_update_callback(const std::vector< rclcpp::Parameter > &parameters)
Callback for dynamic parameter updates.
double caseThreeSpeedProfile(double stop_dist, double current_speed, double stop_time) const
Determine the desired speed profile parameters for Case 3.
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.
carma_ros2_utils::SubPtr< carma_planning_msgs::msg::GuidanceState > guidance_state_sub_
carma_ros2_utils::CallbackReturn on_activate_plugin()
Method which is triggered when this plugin is moved from the INACTIVE to ACTIVE states....
rclcpp::TimerBase::SharedPtr mob_op_pub_timer_
bool get_availability()
Get the availability status of this plugin based on the current operating environment....
carma_ros2_utils::PubPtr< carma_v2x_msgs::msg::MobilityOperation > mobility_operation_pub_
void currentPoseCb(geometry_msgs::msg::PoseStamped::UniquePtr msg)
callback function for current pose
void publishMobilityOperation()
Method to publish mobility operation msgs at a fixed rate of 10hz if approaching intersection.
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_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, TurnDirection turn_direction, const lanelet::Id &starting_lane_id, const lanelet::Id &ending_lane_id) const
double calc_speed_before_decel(double stop_time, double stop_dist, double current_speed) const
calculate the speed, right before the car starts to decelerate for stopping
SCIStrategicPluginConfig config_
Config containing configurable algorithm parameters.
carma_v2x_msgs::msg::MobilityOperation generateMobilityOperation()
Generates Mobility Operation messages.
void mobilityOperationCb(carma_v2x_msgs::msg::MobilityOperation::UniquePtr msg)
callback function for mobility operation
carma_ros2_utils::SubPtr< carma_v2x_msgs::msg::BSM > bsm_sub_
double findSpeedLimit(const lanelet::ConstLanelet &llt) const
Given a Lanelet, find it's associated Speed Limit.
std::string get_version_id()
Returns the version id of this plugin.
void caseOneSpeedProfile(double speed_before_decel, double current_speed, double stop_time, std::vector< double > *float_metadata_list) const
Determine the desired speed profile parameters for Case 1.
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, double stopping_accel, rclcpp::Time start_time, rclcpp::Time end_time) const
SCIStrategicPlugin(const rclcpp::NodeOptions &)
Default constructor for RouteFollowingPlugin class.
carma_planning_msgs::msg::Maneuver composeLaneFollowingManeuverMessage(int case_num, double start_dist, double end_dist, double start_speed, double target_speed, rclcpp::Time start_time, double time_to_stop, std::vector< lanelet::Id > lane_ids)
Compose a lane keeping maneuver message based on input params.
void caseTwoSpeedProfile(double stop_dist, double speed_before_decel, double current_speed, double stop_time, double speed_limit, std::vector< double > *float_metadata_list) const
Determine the desired speed profile parameters for Case 2.
auto to_string(const UtmZone &zone) -> std::string
Definition: utm_zone.cpp:21
double getManeuverEndSpeed(const carma_planning_msgs::msg::Maneuver &mvr)
Anonymous function to extract maneuver end speed which can not be optained with GET_MANEUVER_PROPERY ...
#define GET_MANEUVER_PROPERTY(mvr, property)
Struct to store the configuration settings for the WzStrategicPlugin class.
std::string strategic_plugin_name
The name to use for this plugin during comminications with the arbitrator.
double min_maneuver_planning_period
The minimum period in seconds which a maneuver plan must cover if the plugin wishes to control the wh...
std::string lane_following_plugin_name
The name of the tactical plugin to use for Lane Following trajectory planning.
double vehicle_accel_limit_multiplier
A multiplier to apply to the maximum allowable vehicle acceleration limit so we plan under our capabi...
double vehicle_decel_limit_multiplier
A multiplier to apply to the maximum allowable vehicle deceleration limit so we plan under our capabi...
double vehicle_decel_limit
The maximum allowable vehicle deceleration limit in m/s.
std::string stop_and_wait_plugin_name
The name of the plugin to use for stop and wait trajectory planning.
std::string vehicle_id
License plate of the vehicle.
std::string intersection_transit_plugin_name
The name of the plugin to use for intersection transit trajectory planning.
double stop_line_buffer
A buffer infront of the stopping location which will still be considered a valid stop.
double vehicle_accel_limit
The maximum allowable vehicle acceleration limit in m/s.
Struct representing a vehicle state for the purposes of planning.