Carma-platform v4.11.0
CARMA Platform is built on robot operating system (ROS) and utilizes open source software (OSS) that enables Cooperative Driving Automation (CDA) features to allow Automated Driving Systems to interact and cooperate with infrastructure and other vehicles through communication.
stop_controlled_intersection_tactical_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 */
16
17#include <rclcpp/rclcpp.hpp>
18#include <string>
19#include <algorithm>
20#include <memory>
21#include <boost/uuid/uuid_generators.hpp>
22#include <boost/uuid/uuid_io.hpp>
23#include <lanelet2_core/geometry/Point.h>
24#include <trajectory_utils/trajectory_utils.hpp>
25#include <trajectory_utils/conversions/conversions.hpp>
26#include <sstream>
27#include <Eigen/Core>
28#include <Eigen/Geometry>
29#include <Eigen/LU>
30#include <Eigen/SVD>
31#include <unordered_set>
32#include <vector>
33#include <carma_planning_msgs/msg/stop_and_wait_maneuver.hpp>
34#include <lanelet2_core/primitives/Lanelet.h>
35#include <lanelet2_core/geometry/LineString.h>
37#include <carma_wm/Geometry.hpp>
38#include <carma_planning_msgs/msg/trajectory_plan_point.hpp>
39#include <carma_planning_msgs/msg/trajectory_plan.hpp>
40#include <math.h>
41#include <std_msgs/msg/float64.hpp>
43
44using oss = std::ostringstream;
45
47{
48
49namespace std_ph = std::placeholders;
50
53{
54 basic_autonomy::set_logger(get_logger().get_child("basic_autonomy"));
55 // Declare parameters
56 config_.trajectory_time_length = declare_parameter<double>("trajectory_time_length", config_.trajectory_time_length);
57 config_.curve_resample_step_size = declare_parameter<double>("curve_resample_step_size", config_.curve_resample_step_size);
58 config_.centerline_sampling_spacing = declare_parameter<double>("centerline_sampling_spacing", config_.centerline_sampling_spacing);
59 config_.curvature_moving_average_window_size = declare_parameter<int>("curvature_moving_average_window_size", config_.curvature_moving_average_window_size);
60 config_.lateral_accel_limit = declare_parameter<double>("lateral_accel_limit", config_.lateral_accel_limit);
61 config_.speed_moving_average_window_size = declare_parameter<int>("speed_moving_average_window_size", config_.speed_moving_average_window_size);
62 config_.back_distance = declare_parameter<double>("back_distance", config_.back_distance);
63}
64
65rcl_interfaces::msg::SetParametersResult StopControlledIntersectionTacticalPlugin::parameter_update_callback(const std::vector<rclcpp::Parameter> &parameters)
66{
67 auto error_double = update_params<double>({
68 {"trajectory_time_length", config_.trajectory_time_length},
69 {"curve_resample_step_size", config_.curve_resample_step_size},
70 {"centerline_sampling_spacing", config_.centerline_sampling_spacing},
71 {"lateral_accel_limit", config_.lateral_accel_limit},
72 {"back_distance", config_.back_distance}
73 }, parameters);
74
75 auto error_int = update_params<int>({
76 {"curvature_moving_average_window_size", config_.curvature_moving_average_window_size},
77 {"speed_moving_average_window_size", config_.speed_moving_average_window_size}
78 }, parameters);
79
80 rcl_interfaces::msg::SetParametersResult result;
81
82 result.successful = !error_double && !error_int;
83
84 return result;
85}
86
88{
90
91 // Declare parameters
92 get_parameter<double>("trajectory_time_length", config_.trajectory_time_length);
93 get_parameter<double>("curve_resample_step_size", config_.curve_resample_step_size);
94 get_parameter<double>("centerline_sampling_spacing", config_.centerline_sampling_spacing);
95 get_parameter<int>("curvature_moving_average_window_size", config_.curvature_moving_average_window_size);
96 get_parameter<double>("lateral_accel_limit", config_.lateral_accel_limit);
97 get_parameter<int>("speed_moving_average_window_size", config_.speed_moving_average_window_size);
98 get_parameter<double>("back_distance", config_.back_distance);
99
100 // Register runtime parameter update callback
101 add_on_set_parameters_callback(std::bind(&StopControlledIntersectionTacticalPlugin::parameter_update_callback, this, std_ph::_1));
102
103 RCLCPP_INFO_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"),"Done loading parameters: " << config_);
104
105 // set world model pointer
107
108 // Return success if everything initialized successfully
109 return CallbackReturn::SUCCESS;
110}
111
113 std::shared_ptr<rmw_request_id_t> srv_header,
114 carma_planning_msgs::srv::PlanTrajectory::Request::SharedPtr req,
115 carma_planning_msgs::srv::PlanTrajectory::Response::SharedPtr resp)
116{
117 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "Starting stop controlled intersection trajectory planning");
118
119 if(req->maneuver_index_to_plan >= req->maneuver_plan.maneuvers.size())
120 {
121 throw std::invalid_argument(
122 "Stop Control Intersection Plugin asked to plan invalid maneuver index: " + std::to_string(req->maneuver_index_to_plan) +
123 " for plan of size: " + std::to_string(req->maneuver_plan.maneuvers.size()));
124 }
125 std::vector<carma_planning_msgs::msg::Maneuver> maneuver_plan;
126 for(size_t i = req->maneuver_index_to_plan; i < req->maneuver_plan.maneuvers.size(); i++){
127
128 if((req->maneuver_plan.maneuvers[i].type == carma_planning_msgs::msg::Maneuver::LANE_FOLLOWING || req->maneuver_plan.maneuvers[i].type == carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_STRAIGHT
129 || req->maneuver_plan.maneuvers[i].type == carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_LEFT_TURN || req->maneuver_plan.maneuvers[i].type ==carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_RIGHT_TURN)
130 && GET_MANEUVER_PROPERTY(req->maneuver_plan.maneuvers[i], parameters.string_valued_meta_data.front()) == stop_controlled_intersection_strategy_)
131 {
132 maneuver_plan.push_back(req->maneuver_plan.maneuvers[i]);
133 resp->related_maneuvers.push_back(req->maneuver_plan.maneuvers[i].type);
134 }
135 else
136 {
137 break;
138 }
139 }
140
141 lanelet::BasicPoint2d veh_pos(req->vehicle_state.x_pos_global, req->vehicle_state.y_pos_global);
142 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "Planning state x:"<<req->vehicle_state.x_pos_global <<" , y: " << req->vehicle_state.y_pos_global);
143
144 double current_downtrack = wm_->routeTrackPos(veh_pos).downtrack;
145 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "Current_downtrack"<< current_downtrack);
146
147 std::vector<PointSpeedPair> points_and_target_speeds = maneuvers_to_points( maneuver_plan, wm_, req->vehicle_state);
148 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "Maneuver to points size:"<< points_and_target_speeds.size());
149 // RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "Printing points: ");
150 // TODO: add print logic
151 carma_planning_msgs::msg::TrajectoryPlan trajectory;
152 trajectory.header.frame_id = "map";
153 trajectory.header.stamp = req->header.stamp;
154 trajectory.trajectory_id = boost::uuids::to_string(boost::uuids::random_generator()());
155
156 //Add compose trajectory from centerline
157 trajectory.trajectory_points = compose_trajectory_from_centerline(points_and_target_speeds, req->vehicle_state, req->header.stamp);
158 trajectory.initial_longitudinal_velocity = req->vehicle_state.longitudinal_vel;
159
160 // Set the planning plugin field name
161 for (auto& p : trajectory.trajectory_points) {
162 p.planner_plugin_name = get_plugin_name();
163 // p.controller_plugin_name = "PurePursuit";
164 }
165
166 resp->trajectory_plan = trajectory;
167
168 resp->maneuver_status.push_back(carma_planning_msgs::srv::PlanTrajectory::Response::MANEUVER_IN_PROGRESS);
169}
170
171std::vector<PointSpeedPair> StopControlledIntersectionTacticalPlugin::maneuvers_to_points(const std::vector<carma_planning_msgs::msg::Maneuver>& maneuvers,
172 const carma_wm::WorldModelConstPtr& wm, const carma_planning_msgs::msg::VehicleState& state)
173{
174 std::vector<PointSpeedPair> points_and_target_speeds;
175 std::unordered_set<lanelet::Id> visited_lanelets;
176
177 lanelet::BasicPoint2d veh_pos(state.x_pos_global, state.y_pos_global);
178 double max_starting_downtrack = wm_->routeTrackPos(veh_pos).downtrack; //The vehicle position
179 double starting_speed = state.longitudinal_vel;
180
181 bool first = true;
182 double starting_downtrack;
183 for (const auto& maneuver : maneuvers)
184 {
185 if(maneuver.type != carma_planning_msgs::msg::Maneuver::LANE_FOLLOWING && maneuver.type != carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_STRAIGHT && maneuver.type != carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_LEFT_TURN
186 && maneuver.type !=carma_planning_msgs::msg::Maneuver::INTERSECTION_TRANSIT_RIGHT_TURN ){
187 throw std::invalid_argument("Stop Controlled Intersection Tactical Plugin does not support this maneuver type");
188 }
189
190 if(first)
191 {
192 starting_downtrack = GET_MANEUVER_PROPERTY(maneuver, start_dist);
193 if (starting_downtrack > max_starting_downtrack)
194 {
195 starting_downtrack = max_starting_downtrack;
196 }
197 first = false;
198 }
199
200 // Sample the lanelet centerline at fixed increments.
201 // std::min call here is a guard against starting_downtrack being within 1m of the maneuver end_dist
202 // in this case the sampleRoutePoints method will return a single point allowing execution to continue
203 std::vector<lanelet::BasicPoint2d> route_points = wm->sampleRoutePoints(
204 std::min(starting_downtrack + config_.centerline_sampling_spacing, GET_MANEUVER_PROPERTY(maneuver,end_dist)),
206
207 route_points.insert(route_points.begin(), veh_pos);
208 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "Route geometery points size: "<<route_points.size());
209 //get case num from maneuver parameters
210 if(GET_MANEUVER_PROPERTY(maneuver,parameters.int_valued_meta_data).empty()){
211 throw std::invalid_argument("No case number specified for stop controlled intersection maneuver");
212 }
213
214 int case_num = GET_MANEUVER_PROPERTY(maneuver,parameters.int_valued_meta_data[0]);
215 if(case_num == 1){
216 points_and_target_speeds = create_case_one_speed_profile(wm, maneuver, route_points, starting_speed, state);
217 }
218 else if(case_num == 2){
219 points_and_target_speeds = create_case_two_speed_profile(wm, maneuver, route_points, starting_speed);
220 }
221 else if(case_num == 3)
222 {
223 points_and_target_speeds = create_case_three_speed_profile(wm, maneuver, route_points, starting_speed);
224 }
225 else{
226 throw std::invalid_argument("The stop controlled intersection tactical plugin doesn't handle the case number requested");
227 }
228 }
229
230 return points_and_target_speeds;
231}
232
234const carma_planning_msgs::msg::Maneuver& maneuver, std::vector<lanelet::BasicPoint2d>& route_geometry_points, double starting_speed, const carma_planning_msgs::msg::VehicleState& state){
235
236 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "Planning for Case One");
237 //Derive meta data values from maneuver message - Using order in sci_strategic_plugin
238 double a_acc = GET_MANEUVER_PROPERTY(maneuver, parameters.float_valued_meta_data[0]);
239 double a_dec = GET_MANEUVER_PROPERTY(maneuver, parameters.float_valued_meta_data[1]); //a_dec is a -ve value
240 double t_acc = GET_MANEUVER_PROPERTY(maneuver, parameters.float_valued_meta_data[2]);
241 double t_dec = GET_MANEUVER_PROPERTY(maneuver, parameters.float_valued_meta_data[3]);
242 double speed_before_decel = GET_MANEUVER_PROPERTY(maneuver, parameters.float_valued_meta_data[4]);
243 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "a_acc received: "<< a_acc);
244 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "a_dec received: "<< a_dec);
245 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "t_acc received: "<< t_acc);
246 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "t_dec received: "<< t_dec);
247 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "speed before decel received: "<< speed_before_decel);
248
249 //Derive start and end dist from maneuver
250 double start_dist = GET_MANEUVER_PROPERTY(maneuver, start_dist);
251 double end_dist = GET_MANEUVER_PROPERTY(maneuver, end_dist);
252
253 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "Maneuver starting downtrack: "<< start_dist);
254 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "Maneuver ending downtrack: "<< end_dist);
255 //Checking state against start_dist and adjust profile
256 lanelet::BasicPoint2d state_point(state.x_pos_global, state.y_pos_global);
257 double route_starting_downtrack = wm->routeTrackPos(state_point).downtrack; //Starting downtrack based on geometry points
258 double dist_acc; //Distance for which acceleration lasts
259
260 if(route_starting_downtrack < start_dist){
261 //Update parameters
262 //Keeping the deceleration part the same
263 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "Starting distance is less than maneuver start, updating parameters");
264 double dist_decel = pow(speed_before_decel, 2)/(2*std::abs(a_dec));
265
266 dist_acc = end_dist - dist_decel;
267 a_acc = (pow(speed_before_decel, 2) - pow(starting_speed,2))/(2*dist_acc);
268 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "Updated a_acc: "<< a_acc);
269 }
270 else{
271 //Use parameters from maneuver message
272 dist_acc = (pow(speed_before_decel, 2) - pow(starting_speed, 2))/(2*a_acc);
273 }
274
275 std::vector<PointSpeedPair> points_and_target_speeds;
277 first_point.point = state_point;
278 first_point.speed = starting_speed;
279 points_and_target_speeds.push_back(first_point);
280
281 lanelet::BasicPoint2d prev_point = state_point;
282 double total_dist_covered = 0; //Starting dist for maneuver treated as 0.0
283
284 for(size_t i = 1; i < route_geometry_points.size(); i++){
285 lanelet::BasicPoint2d current_point = route_geometry_points[i];
286 double delta_d = lanelet::geometry::distance2d(prev_point, current_point);
287 total_dist_covered += delta_d;
288 //Find speed at dist covered
289 double speed_i;
290 if(total_dist_covered <= dist_acc){
291 //Acceleration part
292 speed_i = sqrt(pow(starting_speed,2) + 2*a_acc*total_dist_covered);
293 }
294 else{
295 //Deceleration part
296 speed_i = sqrt(std::max(pow(speed_before_decel,2) + 2*a_dec*(total_dist_covered - dist_acc),0.0)); //std::max to ensure negative value is not sqrt
297 if(speed_i < epsilon_){
298 speed_i = 0.0;
299 }
300 }
301
303 if(speed_i < epsilon_){
304 p.point = prev_point;
305 p.speed = 0.0;
306 }
307 else{
308 p.point = route_geometry_points[i];
309 p.speed = speed_i;
310 prev_point = current_point; //Advance prev point if speed changes
311 }
312 points_and_target_speeds.push_back(p);
313
314 }
315
316 return points_and_target_speeds;
317
318}
319
321const carma_planning_msgs::msg::Maneuver& maneuver, std::vector<lanelet::BasicPoint2d>& route_geometry_points, double starting_speed){
322 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "Planning for Case Two");
323 //Derive meta data values from maneuver message - Using order in sci_strategic_plugin
324 double a_acc = GET_MANEUVER_PROPERTY(maneuver, parameters.float_valued_meta_data[0]);
325 double a_dec = GET_MANEUVER_PROPERTY(maneuver, parameters.float_valued_meta_data[1]); //a_dec is a -ve value
326 double t_acc = GET_MANEUVER_PROPERTY(maneuver, parameters.float_valued_meta_data[2]);
327 double t_dec = GET_MANEUVER_PROPERTY(maneuver, parameters.float_valued_meta_data[3]);
328 double t_cruise = GET_MANEUVER_PROPERTY(maneuver, parameters.float_valued_meta_data[4]);
329 double speed_before_decel = GET_MANEUVER_PROPERTY(maneuver, parameters.float_valued_meta_data[5]);
330
331 //Derive start and end dist from maneuver
332 double start_dist = GET_MANEUVER_PROPERTY(maneuver, start_dist);
333 double end_dist = GET_MANEUVER_PROPERTY(maneuver, end_dist);
334 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "Maneuver starting downtrack: "<< start_dist);
335 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "Maneuver ending downtrack: "<< end_dist);
336
337 //Checking route geometry start against start_dist and adjust profile
338 double route_starting_downtrack = wm->routeTrackPos(route_geometry_points[0]).downtrack; //Starting downtrack based on geometry points
339 double dist_acc; //Distance over which acceleration happens
340 double dist_cruise; //Distance over which cruising happens
341 double dist_decel; //Distance over which deceleration happens
342
343 if(route_starting_downtrack < start_dist){
344 //update parameters
345 //Keeping acceleration and deceleration part same as planned in strategic plugin
346 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "Starting distance is less than maneuver start, updating parameters");
347 dist_acc = starting_speed*t_acc + 0.5 * a_acc * pow(t_acc,2);
348 dist_decel = speed_before_decel*t_dec + 0.5 * a_dec * pow(t_dec,2);
349 dist_cruise = end_dist - route_starting_downtrack - (dist_acc + dist_decel);
350 }
351 else{
352 //Use maneuver parameters to create speed profile
353 dist_acc = starting_speed*t_acc + 0.5 * a_acc * pow(t_acc,2);
354 dist_cruise = speed_before_decel*t_cruise;
355 dist_decel = speed_before_decel*t_dec + 0.5 * a_dec * pow(t_dec,2);
356 }
357
358 //Check calculated total dist against maneuver limits
359 double total_distance_needed = dist_acc + dist_cruise + dist_decel;
360 if(total_distance_needed - (end_dist - start_dist) > epsilon_ ){
361 //Requested maneuver needs to be modified to meet start and end dist req
362 //Sacrifice on cruising and then acceleration if needed
363 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "Updating maneuver to meet start and end dist req.");
364 double delta_total_dist = total_distance_needed - (end_dist - start_dist);
365 dist_cruise -= delta_total_dist;
366 if(dist_cruise < 0){
367 dist_acc += dist_cruise;
368 dist_cruise = 0;
369 }
370 //Not considering dist_acc < 0 after this.
371 }
372
373 std::vector<PointSpeedPair> points_and_target_speeds;
375 first_point.point = route_geometry_points[0];
376 first_point.speed = starting_speed;
377 points_and_target_speeds.push_back(first_point);
378
379 lanelet::BasicPoint2d prev_point = route_geometry_points.front();
380 double total_dist_planned = 0; //Starting dist for maneuver treated as 0.0
381 double prev_speed = starting_speed;
382 for(auto route_point : route_geometry_points){
383 lanelet::BasicPoint2d current_point = route_point;
384 double delta_d = lanelet::geometry::distance2d(prev_point, current_point);
385 total_dist_planned += delta_d;
386
387 //Find speed at dist covered
388 double speed_i;
389 if(total_dist_planned < dist_acc){
390 //Acceleration part
391 speed_i = sqrt(pow(starting_speed,2) + 2*a_acc*total_dist_planned);
392 }
393 else if(dist_cruise > 0 && total_dist_planned >= dist_acc && total_dist_planned <= (dist_acc + dist_cruise)){
394 //Cruising part
395 speed_i = prev_speed;
396 }
397 else{
398 //Deceleration part
399 speed_i = sqrt(std::max(pow(speed_before_decel,2) + 2*a_dec*(total_dist_planned - dist_acc - dist_cruise),0.0));//std::max to ensure negative value is not sqrt
400 }
401
403 if(speed_i < epsilon_){
404 p.point = prev_point;
405 p.speed = 0.0;
406 }
407 else{
408 p.point = route_point;
409 p.speed = std::min(speed_i,speed_before_decel);
410 prev_point = current_point; //Advance prev point if speed changes
411 }
412 points_and_target_speeds.push_back(p);
413
414 prev_speed = speed_i;
415 }
416
417 return points_and_target_speeds;
418
419}
420
422const carma_planning_msgs::msg::Maneuver& maneuver, std::vector<lanelet::BasicPoint2d>& route_geometry_points, double starting_speed){
423 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "Planning for Case three");
424 //Derive meta data values from maneuver message - Using order in sci_strategic_plugin
425 double a_dec = GET_MANEUVER_PROPERTY(maneuver, parameters.float_valued_meta_data[0]);
426
427 //Derive start and end dist from maneuver
428 double start_dist = GET_MANEUVER_PROPERTY(maneuver, start_dist);
429 double end_dist = GET_MANEUVER_PROPERTY(maneuver, end_dist);
430 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "Maneuver starting downtrack: "<< start_dist);
431 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "Maneuver ending downtrack: "<< end_dist);
432
433 //Checking route geometry start against start_dist and adjust profile
434 double route_starting_downtrack = wm->routeTrackPos(route_geometry_points[0]).downtrack; //Starting downtrack based on geometry points
435
436 if(route_starting_downtrack < start_dist){
437 //update parameter
438 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "Starting distance is less than maneuver start, updating parameters");
439 a_dec = pow(starting_speed, 2)/(2*(end_dist - route_starting_downtrack));
440 }
441
442 std::vector<PointSpeedPair> points_and_target_speeds;
444 first_point.point = route_geometry_points[0];
445 first_point.speed = starting_speed;
446 points_and_target_speeds.push_back(first_point);
447
448 lanelet::BasicPoint2d prev_point = route_geometry_points[0];
449 double total_dist_covered = 0; //Starting dist for maneuver treated as 0.0
450
451 for(size_t i = 0;i < route_geometry_points.size(); i++){
452 lanelet::BasicPoint2d current_point = route_geometry_points[i];
453 double delta_d = lanelet::geometry::distance2d(prev_point, current_point);
454 total_dist_covered +=delta_d;
455 //Find speed at dist covered
456 double speed_i = sqrt(std::max(pow(starting_speed,2) + 2 * a_dec * total_dist_covered, 0.0)); //std::max to ensure negative value is not sqrt
457
459
460 if(speed_i < epsilon_){
461 p.point = prev_point;
462 p.speed = 0.0;
463 }
464 else{
465 p.point = route_geometry_points[i];
466 p.speed = speed_i;
467 prev_point = current_point; //Advance prev point if speed changes
468 }
469
470 points_and_target_speeds.push_back(p);
471
472
473 }
474
475 return points_and_target_speeds;
476}
477
478std::vector<carma_planning_msgs::msg::TrajectoryPlanPoint> StopControlledIntersectionTacticalPlugin::compose_trajectory_from_centerline(
479 const std::vector<PointSpeedPair>& points, const carma_planning_msgs::msg::VehicleState& state, const rclcpp::Time& state_time){
480
481 std::vector<carma_planning_msgs::msg::TrajectoryPlanPoint> trajectory;
482 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "VehicleState: "
483 << " x: " << state.x_pos_global << " y: " << state.y_pos_global << " yaw: " << state.orientation
484 << " speed: " << state.longitudinal_vel);
485
486 int nearest_pt_index = basic_autonomy::waypoint_generation::get_nearest_point_index(points, state);
487 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "Nearest pt index: "<<nearest_pt_index);
488 std::vector<PointSpeedPair> future_points(points.begin() + nearest_pt_index + 1, points.end()); //Points in front of current vehicle position
489 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "Future points size: "<<future_points.size());
491 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "Got time bound points with size:" << time_bound_points.size());
492
493 //Attach past points
494 std::vector<PointSpeedPair> back_and_future = attach_past_points(points, time_bound_points, nearest_pt_index, config_.back_distance);
495 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "Got back_and_future points with size: "<<back_and_future.size());
496
497 std::vector<double> speed_limits;
498 std::vector<lanelet::BasicPoint2d> curve_points;
499 split_point_speed_pairs(time_bound_points, &curve_points, &speed_limits);
500
501 std::unique_ptr<basic_autonomy::smoothing::SplineI> fit_curve = basic_autonomy::waypoint_generation::compute_fit(curve_points); //Compute splines based on curve points
502 if(!fit_curve)
503 {
504 throw std::invalid_argument("Could not fit a spline curve along the trajectory!");
505 }
506
507 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "Got fit");
508 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "Speed_limits.size(): "<<speed_limits.size());
509
510 std::vector<lanelet::BasicPoint2d> all_sampling_points;
511 all_sampling_points.reserve(1 + curve_points.size() * 2);
512
513 std::vector<double> distributed_speed_limits;
514 distributed_speed_limits.reserve(1+ curve_points.size() * 2);
515
516 //Compute total length of the trajectory to get correct number of points
517 // we expect using curve resample step size
518 std::vector<double> downtracks_raw = carma_wm::geometry::compute_arc_lengths(curve_points);
519
520 auto total_step_along_curve = static_cast<int>(downtracks_raw.back() / config_.curve_resample_step_size);
521
522 int current_speed_index = 0;
523 size_t total_point_size = curve_points.size();
524
525 double step_threshold_for_next_speed = (double)total_step_along_curve / (double)total_point_size;
526 double scaled_steps_along_curve = 0.0; // from 0 (start) to 1 (end) for the whole trajectory
527 std::vector<double> better_curvature;
528 better_curvature.reserve(1 + curve_points.size() * 2);
529
530 for (size_t steps_along_curve = 0; steps_along_curve < total_step_along_curve; steps_along_curve++) // Resample curve at tighter resolution
531 {
532 lanelet::BasicPoint2d p = (*fit_curve)(scaled_steps_along_curve);
533 all_sampling_points.push_back(p);
534 double c = basic_autonomy::waypoint_generation::compute_curvature_at((*fit_curve), scaled_steps_along_curve);
535 better_curvature.push_back(c);
536
537 if((double) steps_along_curve > step_threshold_for_next_speed)
538 {
539 step_threshold_for_next_speed += (double)total_step_along_curve / (double)total_point_size;
540 current_speed_index++;
541 }
542 distributed_speed_limits.push_back(speed_limits[current_speed_index]); //Identify speed limits for resampled points
543 scaled_steps_along_curve += 1.0 / total_step_along_curve; //adding steps_along_curve_step_size
544 }
545
546 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "Got sampled points with size:" << all_sampling_points.size());
547
548 std::vector<double> final_yaw_values = carma_wm::geometry::compute_tangent_orientations(all_sampling_points);
549
550 std::vector<double> curvatures = basic_autonomy::smoothing::moving_average_filter(better_curvature, config_.curvature_moving_average_window_size, false);
551 std::vector<double> ideal_speeds =
552 trajectory_utils::constrained_speeds_for_curvatures(curvatures, config_.lateral_accel_limit);
553
554 std::vector<double> constrained_speed_limits = basic_autonomy::waypoint_generation::apply_speed_limits(ideal_speeds, distributed_speed_limits); //Speed min(ideal, calculated)
555 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "Processed all points in computed fit");
556 std::vector<double> final_actual_speeds = constrained_speed_limits;
557
558 if (all_sampling_points.empty())
559 {
560 RCLCPP_WARN_STREAM(rclcpp::get_logger("stop_controlled_intersection_tactical_plugin"), "No trajectory points could be generated");
561 return {};
562 }
563
564 //Drop Past points
565 nearest_pt_index = basic_autonomy::waypoint_generation::get_nearest_index_by_downtrack(all_sampling_points, wm_, state);
566 std::vector<lanelet::BasicPoint2d> future_basic_points(all_sampling_points.begin() + nearest_pt_index + 1,
567 all_sampling_points.end());
568 std::vector<double> future_speeds(final_actual_speeds.begin() + nearest_pt_index + 1,
569 final_actual_speeds.end());
570 std::vector<double> future_yaw(final_yaw_values.begin() + nearest_pt_index + 1,
571 final_yaw_values.end());
572
573 // Add current vehicle point to front of the trajectory
574 lanelet::BasicPoint2d cur_veh_point(state.x_pos_global, state.y_pos_global);
575
576 future_basic_points.insert(future_basic_points.begin(),
577 cur_veh_point); // Add current vehicle position to front of sample points
578 future_speeds.insert(future_speeds.begin(), state.longitudinal_vel);
579 future_yaw.insert(future_yaw.begin(), state.orientation);
580
581 // Compute points to local downtracks
582 std::vector<double> downtracks = carma_wm::geometry::compute_arc_lengths(future_basic_points);
583
585
586 // Convert speeds to times
587 std::vector<double> times;
588
589 //Force last point speed to 0.0 if close to end
590 if(lanelet::geometry::distance2d(future_basic_points.back(), points.back().point) < epsilon_){
591 final_actual_speeds.back() = 0.0;
592 }
593
594 trajectory_utils::conversions::speed_to_time(downtracks, final_actual_speeds, &times);
595
596 // Build trajectory points
597 std::vector<carma_planning_msgs::msg::TrajectoryPlanPoint> traj_points =
598 basic_autonomy::waypoint_generation::trajectory_from_points_times_orientations(future_basic_points, times, future_yaw, state_time, "default");
599
600 return traj_points;
601}
602
604{
605 return true;
606}
607
609{
610 return "v1.0";
611}
612
613} // namespace SCI_strategic_plugin
614
615#include "rclcpp_components/register_node_macro.hpp"
616
617// Register the component with class_loader
#define GET_MANEUVER_PROPERTY(mvr, property)
Macro definition to enable easier access to fields shared across the maneuver types.
std::string get_plugin_name() const
Return the name of this plugin.
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...
Class containing primary business logic for the Stop Controlled Intersection Tactical Plugin.
rcl_interfaces::msg::SetParametersResult parameter_update_callback(const std::vector< rclcpp::Parameter > &parameters)
bool get_availability()
Get the availability status of this plugin based on the current operating environment....
std::vector< PointSpeedPair > maneuvers_to_points(const std::vector< carma_planning_msgs::msg::Maneuver > &maneuvers, const carma_wm::WorldModelConstPtr &wm, const carma_planning_msgs::msg::VehicleState &state)
Converts a set of requested stop controlled intersection maneuvers to point speed limit pairs.
std::vector< PointSpeedPair > create_case_two_speed_profile(const carma_wm::WorldModelConstPtr &wm, const carma_planning_msgs::msg::Maneuver &maneuver, std::vector< lanelet::BasicPoint2d > &route_geometry_points, double starting_speed)
Creates a speed profile according to case two of the stop controlled intersection,...
void plan_trajectory_callback(std::shared_ptr< rmw_request_id_t >, carma_planning_msgs::srv::PlanTrajectory::Request::SharedPtr req, carma_planning_msgs::srv::PlanTrajectory::Response::SharedPtr resp) override
Extending class provided callback which should return a planned trajectory based on the provided traj...
carma_ros2_utils::CallbackReturn on_configure_plugin() override
Method which is triggered when this plugin is moved from the UNCONFIGURED to INACTIVE states....
std::vector< carma_planning_msgs::msg::TrajectoryPlanPoint > compose_trajectory_from_centerline(const std::vector< PointSpeedPair > &points, const carma_planning_msgs::msg::VehicleState &state, const rclcpp::Time &state_time)
Method converts a list of lanelet centerline points and current vehicle state into a usable list of t...
std::vector< PointSpeedPair > create_case_one_speed_profile(const carma_wm::WorldModelConstPtr &wm, const carma_planning_msgs::msg::Maneuver &maneuver, std::vector< lanelet::BasicPoint2d > &route_geometry_points, double starting_speed, const carma_planning_msgs::msg::VehicleState &states)
Creates a speed profile according to case one of the stop controlled intersection,...
std::vector< PointSpeedPair > create_case_three_speed_profile(const carma_wm::WorldModelConstPtr &wm, const carma_planning_msgs::msg::Maneuver &maneuver, std::vector< lanelet::BasicPoint2d > &route_geometry_points, double starting_speed)
Creates a speed profile according to case three of the stop controlled intersection,...
std::ostringstream oss
std::vector< double > moving_average_filter(const std::vector< double > input, int window_size, bool ignore_first_point=true)
Extremely simplie moving average filter.
Definition: filters.cpp:24
void split_point_speed_pairs(const std::vector< PointSpeedPair > &points, std::vector< lanelet::BasicPoint2d > *basic_points, std::vector< double > *speeds)
Helper method to split a list of PointSpeedPair into separate point and speed lists.
int get_nearest_point_index(const std::vector< lanelet::BasicPoint2d > &points, const carma_planning_msgs::msg::VehicleState &state)
Returns the nearest point (in terms of cartesian 2d distance) to the provided vehicle pose in the pro...
std::unique_ptr< basic_autonomy::smoothing::SplineI > compute_fit(const std::vector< lanelet::BasicPoint2d > &basic_points)
Computes a spline based on the provided points.
int get_nearest_index_by_downtrack(const std::vector< lanelet::BasicPoint2d > &points, const carma_wm::WorldModelConstPtr &wm, double target_downtrack)
Returns the nearest "less than" point to the provided vehicle pose in the provided list by utilizing ...
std::vector< double > apply_speed_limits(const std::vector< double > speeds, const std::vector< double > speed_limits)
Applies the provided speed limits to the provided speeds such that each element is capped at its corr...
std::vector< carma_planning_msgs::msg::TrajectoryPlanPoint > trajectory_from_points_times_orientations(const std::vector< lanelet::BasicPoint2d > &points, const std::vector< double > &times, const std::vector< double > &yaws, rclcpp::Time startTime, const std::string &desired_controller_plugin)
Method combines input points, times, orientations, and an absolute start time to form a valid carma p...
double compute_curvature_at(const basic_autonomy::smoothing::SplineI &fit_curve, double step_along_the_curve)
Given the curvature fit, computes the curvature at the given step along the curve.
std::vector< PointSpeedPair > constrain_to_time_boundary(const std::vector< PointSpeedPair > &points, double time_span)
Reduces the input points to only those points that fit within the provided time boundary.
std::vector< PointSpeedPair > attach_past_points(const std::vector< PointSpeedPair > &points_set, std::vector< PointSpeedPair > future_points, const int nearest_pt_index, double back_distance)
Attaches back_distance length of points behind the future points.
void set_logger(rclcpp::Logger logger)
Replace the module-level logger used by all basic_autonomy functions.
Definition: log.cpp:33
rclcpp::Logger get_logger()
Return the module-level logger used by all basic_autonomy functions.
Definition: log.cpp:32
auto to_string(const UtmZone &zone) -> std::string
Definition: utm_zone.cpp:21
std::vector< double > compute_tangent_orientations(const lanelet::BasicLineString2d &centerline)
Compute an approximate orientation for the vehicle at each point along the provided centerline.
Definition: Geometry.cpp:565
std::vector< double > compute_arc_lengths(const std::vector< lanelet::BasicPoint2d > &data)
Compute the arc length at each point around the curve.
Definition: Geometry.cpp:498
std::shared_ptr< const WorldModel > WorldModelConstPtr
Definition: WorldModel.hpp:454
list first_point
Definition: process_bag.py:52
Stuct containing the algorithm configuration values for the StopControlledIntersectionTacticalPlugin.