17#include <rclcpp/rclcpp.hpp>
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>
27#include <carma_ros2_utils/carma_lifecycle_node.hpp>
29#include <Eigen/Geometry>
32#include <unordered_set>
35#include <carma_planning_msgs/msg/stop_and_wait_maneuver.hpp>
37#include <carma_planning_msgs/msg/trajectory_plan_point.hpp>
38#include <carma_planning_msgs/msg/trajectory_plan.hpp>
39#include <lanelet2_core/primitives/Lanelet.h>
40#include <lanelet2_core/geometry/LineString.h>
43#include <std_msgs/msg/float64.hpp>
47using oss = std::ostringstream;
55 const std::string& plugin_name,
57 : version_id_ (
version_id),plugin_name_(plugin_name),config_(config),nh_(nh), wm_(wm)
62bool StopandWait::plan_trajectory_cb(carma_planning_msgs::srv::PlanTrajectory::Request::SharedPtr req, carma_planning_msgs::srv::PlanTrajectory::Response::SharedPtr resp)
64 std::chrono::system_clock::time_point start_time = std::chrono::system_clock::now();
65 RCLCPP_DEBUG_STREAM(
rclcpp::get_logger(
"stop_and_wait_plugin"),
"Starting stop&wait planning");
67 if (req->maneuver_index_to_plan >= req->maneuver_plan.maneuvers.size())
69 throw std::invalid_argument(
70 "StopAndWait plugin asked to plan invalid maneuver index: " +
std::to_string(req->maneuver_index_to_plan) +
71 " for plan of size: " +
std::to_string(req->maneuver_plan.maneuvers.size()));
74 if (req->maneuver_plan.maneuvers[req->maneuver_index_to_plan].type != carma_planning_msgs::msg::Maneuver::STOP_AND_WAIT)
76 throw std::invalid_argument(
"StopAndWait plugin asked to plan non STOP_AND_WAIT maneuver");
79 lanelet::BasicPoint2d veh_pos(req->vehicle_state.x_pos_global, req->vehicle_state.y_pos_global);
81 RCLCPP_DEBUG_STREAM(
rclcpp::get_logger(
"stop_and_wait_plugin"),
"planning state x:" << req->vehicle_state.x_pos_global <<
", y: " << req->vehicle_state.y_pos_global <<
", speed: " << req->vehicle_state.longitudinal_vel);
83 if (req->vehicle_state.longitudinal_vel <
epsilon_)
85 RCLCPP_DEBUG_STREAM(
rclcpp::get_logger(
"stop_and_wait_plugin"),
"Detected that car is already stopped! Ignoring the request to plan Stop&Wait");
90 double current_downtrack =
wm_->routeTrackPos(veh_pos).downtrack;
92 RCLCPP_DEBUG_STREAM(
rclcpp::get_logger(
"stop_and_wait_plugin"),
"Current_downtrack" << current_downtrack);
94 if (req->maneuver_plan.maneuvers[req->maneuver_index_to_plan].stop_and_wait_maneuver.end_dist < current_downtrack)
96 throw std::invalid_argument(
"StopAndWait plugin asked to plan maneuver that ends earlier than the current state.");
99 resp->related_maneuvers.push_back(req->maneuver_index_to_plan);
100 resp->maneuver_status.push_back(carma_planning_msgs::srv::PlanTrajectory::Response::MANEUVER_IN_PROGRESS);
102 std::string maneuver_id = req->maneuver_plan.maneuvers[req->maneuver_index_to_plan].stop_and_wait_maneuver.parameters.maneuver_id;
104 RCLCPP_INFO_STREAM(
rclcpp::get_logger(
"stop_and_wait_plugin"),
"Maneuver not yet planned, planning new trajectory");
107 std::vector<carma_planning_msgs::msg::Maneuver> maneuver_plan = { req->maneuver_plan.maneuvers[req->maneuver_index_to_plan] };
110 maneuver_plan,
wm_, req->vehicle_state);
113 carma_planning_msgs::msg::TrajectoryPlan trajectory;
114 trajectory.header.frame_id =
"map";
115 trajectory.header.stamp = req->header.stamp;
121 double stopping_accel = 0.0;
122 if (maneuver_plan[0].stop_and_wait_maneuver.parameters.presence_vector &
123 carma_planning_msgs::msg::ManeuverParameters::HAS_FLOAT_META_DATA)
125 if(maneuver_plan[0].stop_and_wait_maneuver.parameters.float_valued_meta_data.size() < 2){
126 throw std::invalid_argument(
"stop and wait maneuver message missing required meta data");
128 stop_location_buffer = maneuver_plan[0].stop_and_wait_maneuver.parameters.float_valued_meta_data[0];
129 stopping_accel = maneuver_plan[0].stop_and_wait_maneuver.parameters.float_valued_meta_data[1];
131 RCLCPP_DEBUG_STREAM(
rclcpp::get_logger(
"stop_and_wait_plugin"),
"Using stop buffer from meta data: " << stop_location_buffer);
132 RCLCPP_DEBUG_STREAM(
rclcpp::get_logger(
"stop_and_wait_plugin"),
"Using stopping acceleration from meta data: "<< stopping_accel);
135 throw std::invalid_argument(
"stop and wait maneuver message missing required float meta data");
138 double initial_speed = req->vehicle_state.longitudinal_vel;
140 RCLCPP_DEBUG_STREAM(
rclcpp::get_logger(
"stop_and_wait_plugin"),
"Original size: " << points_and_target_speeds.size());
143 points_and_target_speeds, current_downtrack, req->vehicle_state.longitudinal_vel,
144 maneuver_plan[0].stop_and_wait_maneuver.end_dist, stop_location_buffer, req->header.stamp, stopping_accel, initial_speed);
146 RCLCPP_DEBUG_STREAM(
rclcpp::get_logger(
"stop_and_wait_plugin"),
"Trajectory points size:" << trajectory.trajectory_points.size());
148 trajectory.initial_longitudinal_velocity = initial_speed;
150 resp->trajectory_plan = trajectory;
152 std::chrono::system_clock::time_point end_time = std::chrono::system_clock::now();
154 auto duration = end_time - start_time;
155 RCLCPP_DEBUG_STREAM(
rclcpp::get_logger(
"stop_and_wait_plugin"),
"ExecutionTime Stop&Wait Trajectory: " << std::chrono::duration<double>(duration).count());
163 const carma_planning_msgs::msg::VehicleState& state)
165 std::vector<PointSpeedPair> points_and_target_speeds;
166 std::unordered_set<lanelet::Id> visited_lanelets;
168 carma_planning_msgs::msg::StopAndWaitManeuver stop_and_wait_maneuver = maneuvers[0].stop_and_wait_maneuver;
170 lanelet::BasicPoint2d veh_pos(state.x_pos_global, state.y_pos_global);
171 double starting_downtrack =
wm_->routeTrackPos(veh_pos).downtrack;
172 double starting_speed = state.longitudinal_vel;
177 std::vector<lanelet::BasicPoint2d> route_points = wm->sampleRoutePoints(
182 route_points.insert(route_points.begin(), veh_pos);
185 for (
const auto& p : route_points)
189 pair.
speed = starting_speed;
190 points_and_target_speeds.push_back(pair);
193 return points_and_target_speeds;
197 const std::vector<lanelet::BasicPoint2d>& points,
const std::vector<double>& times,
const std::vector<double>& yaws,
198 rclcpp::Time startTime)
200 if (points.size() != times.size() || points.size() != yaws.size())
202 throw std::invalid_argument(
"All input vectors must have the same size");
205 std::vector<carma_planning_msgs::msg::TrajectoryPlanPoint> traj;
206 traj.reserve(points.size());
208 for (
size_t i = 0;
i < points.size();
i++)
210 carma_planning_msgs::msg::TrajectoryPlanPoint tpp;
211 rclcpp::Duration relative_time = rclcpp::Duration::from_nanoseconds(times[
i] * 1e9);
212 tpp.target_time = startTime + relative_time;
213 tpp.x = points[
i].x();
214 tpp.y = points[
i].y();
217 tpp.controller_plugin_name =
"default";
226 const std::vector<PointSpeedPair>& points,
double starting_downtrack,
double starting_speed,
double stop_location,
227 double stop_location_buffer, rclcpp::Time start_time,
double stopping_acceleration,
double& initial_speed)
229 std::vector<carma_planning_msgs::msg::TrajectoryPlanPoint> plan;
230 if (points.size() == 0)
232 RCLCPP_WARN_STREAM(
rclcpp::get_logger(
"stop_and_wait_plugin"),
"No points to use as trajectory in stop and wait plugin");
236 std::vector<PointSpeedPair> final_points;
238 double half_stopping_buffer = stop_location_buffer * 0.5;
239 double remaining_distance = stop_location - half_stopping_buffer - starting_downtrack;
242 double req_dist = (starting_speed * starting_speed) /
243 (2.0 * target_accel);
247 while (remaining_distance <= 0.0)
249 if(remaining_distance <= (stop_location - starting_downtrack))
252 remaining_distance += 0.2;
259 if (req_dist > remaining_distance)
262 RCLCPP_DEBUG_STREAM(
rclcpp::get_logger(
"stop_and_wait_plugin"),
"Target Accel Update From: " << target_accel);
264 (starting_speed * starting_speed) / (2.0 * remaining_distance);
266 RCLCPP_DEBUG_STREAM(
rclcpp::get_logger(
"stop_and_wait_plugin"),
"Target Accel Update To: " << target_accel);
270 std::vector<double> inverse_downtracks;
271 inverse_downtracks.reserve(points.size());
272 final_points.reserve(points.size());
275 prev_pair.
speed = 0.0;
276 final_points.push_back(prev_pair);
277 inverse_downtracks.push_back(0);
279 bool reached_end =
false;
280 for (
int i = points.size() - 2;
i >= 0;
i--)
283 double v_i = prev_pair.
speed;
284 double dx = lanelet::geometry::distance2d(prev_pair.
point, points[
i].point);
285 double new_downtrack = inverse_downtracks.back() +
dx;
287 if (new_downtrack < half_stopping_buffer) {
290 final_points.push_back(pair);
291 inverse_downtracks.push_back(new_downtrack);
296 if (reached_end || v_i >= starting_speed)
301 pair.
speed = starting_speed;
302 final_points.push_back(pair);
303 inverse_downtracks.push_back(new_downtrack);
308 double v_f = sqrt(v_i * v_i + 2 * target_accel *
dx);
311 pair.
speed = std::min(v_f, starting_speed);
312 final_points.push_back(pair);
313 inverse_downtracks.push_back(new_downtrack);
319 std::reverse(final_points.begin(),
322 std::vector<double> speeds;
323 std::vector<lanelet::BasicPoint2d> raw_points;
327 double max_downtrack = inverse_downtracks.back();
328 std::vector<double> downtracks = lanelet::utils::transform(inverse_downtracks, [max_downtrack](
const auto& d) {
return max_downtrack - d; });
329 std::reverse(downtracks.begin(),
332 bool in_range =
false;
333 double stopped_downtrack = 0;
334 lanelet::BasicPoint2d stopped_point;
336 bool vehicle_in_buffer = downtracks.back() < stop_location_buffer;
340 for (
size_t i = 0;
i < filtered_speeds.size();
i++)
342 double downtrack = downtracks[
i];
344 constexpr double one_mph_in_mps = 0.44704;
346 if (downtracks.back() - downtrack < stop_location_buffer && filtered_speeds[
i] <
config_.
crawl_speed + one_mph_in_mps)
350 if (vehicle_in_buffer || (
i == filtered_speeds.size() - 1)) {
351 filtered_speeds[
i] = 0.0;
363 std::vector<double> times;
364 trajectory_utils::conversions::speed_to_time(downtracks, filtered_speeds, ×);
366 for (
size_t i = 0;
i < times.size();
i++)
368 if (times[
i] != 0 && !std::isnormal(times[
i]) &&
i != 0)
371 *
nh_->get_clock(), 1000,
372 "(Throttled Log 1s) Detected non-normal (nan, inf, etc.) time. Making it same as before: "
375 times[
i] = times[
i - 1];
381 for (
size_t i = 0;
i < points.size();
i++)
383 RCLCPP_DEBUG_STREAM(
rclcpp::get_logger(
"stop_and_wait_plugin"),
"1d: " << downtracks[
i] <<
" t: " << times[
i] <<
" v: " << filtered_speeds[
i]);
388 while (rclcpp::Time(traj.back().target_time) - rclcpp::Time(traj.front().target_time) < rclcpp::Duration::from_nanoseconds(
config_.
minimal_trajectory_duration * 1e9))
390 carma_planning_msgs::msg::TrajectoryPlanPoint new_point = traj.back();
391 new_point.target_time = rclcpp::Time(new_point.target_time) + rclcpp::Duration::from_nanoseconds(
config_.
stop_timestep * 1e9);
393 traj.push_back(new_point);
396 if (!filtered_speeds.empty())
397 initial_speed = filtered_speeds.front();
403 std::vector<lanelet::BasicPoint2d>* basic_points,
404 std::vector<double>* speeds)
const
406 basic_points->reserve(points.size());
407 speeds->reserve(points.size());
409 for (
const auto& p : points)
411 basic_points->push_back(p.point);
412 speeds->push_back(p.speed);
carma_wm::WorldModelConstPtr wm_
StopandWaitConfig config_
void splitPointSpeedPairs(const std::vector< PointSpeedPair > &points, std::vector< lanelet::BasicPoint2d > *basic_points, std::vector< double > *speeds) const
Helper method to split a list of PointSpeedPair into separate point and speed lists.
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_AND_WAIT maneuvers to point speed limit pairs.
bool plan_trajectory_cb(carma_planning_msgs::srv::PlanTrajectory::Request::SharedPtr req, carma_planning_msgs::srv::PlanTrajectory::Response::SharedPtr resp)
Service callback for trajectory planning.
std::vector< carma_planning_msgs::msg::TrajectoryPlanPoint > compose_trajectory_from_centerline(const std::vector< PointSpeedPair > &points, double starting_downtrack, double starting_speed, double stop_location, double stop_location_buffer, rclcpp::Time start_time, double stopping_acceleration, double &initial_speed)
Method converts a list of lanelet centerline points and current vehicle state into a usable list of t...
StopandWait(std::shared_ptr< carma_ros2_utils::CarmaLifecycleNode > nh, carma_wm::WorldModelConstPtr wm, const StopandWaitConfig &config, const std::string &plugin_name, const std::string &version_id)
Constructor.
std::shared_ptr< carma_ros2_utils::CarmaLifecycleNode > nh_
std::vector< carma_planning_msgs::msg::TrajectoryPlanPoint > trajectory_from_points_times_orientations(const std::vector< lanelet::BasicPoint2d > &points, const std::vector< double > ×, const std::vector< double > &yaws, rclcpp::Time startTime)
std::vector< double > moving_average_filter(const std::vector< double > input, int window_size, bool ignore_first_point=true)
Extremely simplie moving average filter.
void set_logger(rclcpp::Logger logger)
Replace the module-level logger used by all basic_autonomy functions.
rclcpp::Logger get_logger()
Return the module-level logger used by all basic_autonomy functions.
auto to_string(const UtmZone &zone) -> std::string
std::vector< double > compute_tangent_orientations(const lanelet::BasicLineString2d ¢erline)
Compute an approximate orientation for the vehicle at each point along the provided centerline.
std::shared_ptr< const WorldModel > WorldModelConstPtr
Stuct containing the algorithm configuration values for the stop_and_wait_plugin.
double centerline_sampling_spacing
double default_stopping_buffer
double accel_limit_multiplier
double minimal_trajectory_duration
double moving_average_window_size
Convenience class for pairing 2d points with speeds.
lanelet::BasicPoint2d point