18#include <boost/uuid/uuid.hpp>
19#include <boost/uuid/uuid_generators.hpp>
20#include <carma_ros2_utils/containers/containers.hpp>
21#include <lanelet2_core/Attribute.h>
22#include <lanelet2_core/geometry/LineString.h>
23#include <lanelet2_core/primitives/Traits.h>
29 rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr logger, rclcpp::Clock::SharedPtr clock)
30 : traffic_control_pub_(traffic_control_pub), wm_(wm), logger_(logger), clock_(clock) {}
35 if(mobility_msg->strategy==
"carma3/Incident_Use_Case")
43 carma_v2x_msgs::msg::TrafficControlMessage traffic_control_msg;
44 traffic_control_msg.choice = carma_v2x_msgs::msg::TrafficControlMessage::TCMV01;
47 traffic_control_msg.tcm_v01=traffic_msg;
67 std::vector<std::string> vec={};
68 std::string delimiter =
",";
71 while ((pos = mobility_strategy_params.find(delimiter)) != std::string::npos)
73 token = mobility_strategy_params.substr(0, pos);
75 mobility_strategy_params.erase(0, pos + delimiter.length());
77 vec.push_back(mobility_strategy_params);
81 RCLCPP_ERROR_STREAM(
logger_->get_logger(),
"Given mobility strategy params are not correctly formatted.");
85 std::string lat_str=vec[0];
86 std::string lon_str=vec[1];
87 std::string downtrack_str=vec[2];
88 std::string uptrack_str=vec[3];
89 std::string min_gap_str=vec[4];
90 std::string speed_advisory_str=vec[5];
91 std::string event_reason_str=vec[6];
92 std::string event_type_str=vec[7];
98 double constexpr APPROXIMATE_DEG_PER_5M = 0.00005;
99 double delta_lat = temp_lat -
latitude;
101 double approximate_degree_delta = sqrt(delta_lat*delta_lat + delta_lon*delta_lon);
103 double temp_down_track=stod(
stringParserHelper(downtrack_str,downtrack_str.find_last_of(
"down_track:")));
104 double temp_up_track=stod(
stringParserHelper(uptrack_str,uptrack_str.find_last_of(
"up_track:")));
105 double temp_min_gap=stod(
stringParserHelper(min_gap_str,min_gap_str.find_last_of(
"min_gap:")));
106 double temp_speed_advisory=stod(
stringParserHelper(speed_advisory_str,speed_advisory_str.find_last_of(
"advisory_speed:")));
107 std::string temp_event_reason=
stringParserHelper(event_reason_str,event_reason_str.find_last_of(
"event_reason:"));
108 std::string temp_event_type=
stringParserHelper(event_type_str,event_type_str.find_last_of(
"event_type:"));
110 if ( approximate_degree_delta < APPROXIMATE_DEG_PER_5M
118 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"Strategy params are unchanged so ignoring new message: " << mobility_strategy_params
119 <<
" degree_delta: " << approximate_degree_delta
141 std::string str_temp=
"";
142 for(
size_t i=str_index+1;
i<str.length();
i++)
151 lanelet::projection::LocalFrameProjector projector(
projection_msg_.c_str());
152 lanelet::GPSPoint gps_point;
156 auto local_point3d = projector.forward(gps_point);
157 return {local_point3d.x(), local_point3d.y()};
164 const lanelet::BasicPoint2d&
point)
166 double min_distance = std::numeric_limits<double>::max();
168 size_t best_index = 0;
169 for (
const auto& p : points)
171 double distance = lanelet::geometry::distance2d(p,
point);
172 if (distance < min_distance)
175 min_distance = distance;
184 const lanelet::BasicPoint2d& start_point,
double downtrack, std::vector<std::vector<lanelet::BasicPoint2d>>* forward_lanes)
const
186 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"getAdjacentForwardCenterlines");
187 for (
const auto& ll : adjacentSet) {
188 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"Processing adjacent lanelet: " << ll.id());
189 std::vector<lanelet::BasicPoint2d> following_lane;
197 lanelet::BasicPoint2d prev_point = cur_ll.centerline()[p_idx].basicPoint2d();
199 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"nearest point" << cur_ll.centerline()[p_idx].id() <<
" : " << prev_point.x() <<
", " << prev_point.y());
201 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"p_idx: " << p_idx);
204 while (dist < downtrack) {
205 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"Accumulating lanelet: " << cur_ll.id());
206 if (p_idx == cur_ll.centerline().size()) {
207 auto next_lls =
wm_->getMapRoutingGraph()->following(cur_ll,
false);
208 if (next_lls.empty()) {
209 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"No followers");
212 const auto& next = next_lls[0];
213 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"Getting next lanelet: " << next.id());
217 if (p_idx != 0 || dist == 0) {
218 following_lane.push_back(lanelet::traits::to2D(cur_ll.centerline()[p_idx]));
219 dist += lanelet::geometry::distance2d(prev_point, following_lane.back());
221 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"distance " << dist);
222 prev_point = lanelet::traits::to2D(cur_ll.centerline()[p_idx]);
225 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"Adding lane with size: " << following_lane.size());
226 forward_lanes->emplace_back(following_lane);
231 const lanelet::BasicPoint2d& start_point,
double uptrack, std::vector<std::vector<lanelet::BasicPoint2d>>* reverse_lanes)
const
233 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"getAdjacentReverseCenterlines");
234 for (
const auto& ll : adjacentSet) {
235 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"Processing adjacent lanelet: " << ll.id());
236 std::vector<lanelet::BasicPoint2d> previous_lane;
243 lanelet::BasicPoint2d prev_point = cur_ll.centerline()[p_idx].basicPoint2d();
245 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"nearest point" << cur_ll.centerline()[p_idx].id() <<
" : " << prev_point.x() <<
", " << prev_point.y());
247 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"p_idx: " << p_idx);
250 while (dist < uptrack) {
251 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"Accumulating lanelet: " << cur_ll.id());
253 auto next_lls =
wm_->getMapRoutingGraph()->previous(cur_ll,
false);
254 if (next_lls.empty()) {
255 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"No previous lanelets");
258 const auto& next = next_lls[0];
259 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"Getting next lanelet: " << next.id());
261 p_idx = cur_ll.centerline().size() - 1;
263 if (p_idx != cur_ll.centerline().size() - 1 || dist == 0) {
265 previous_lane.push_back(lanelet::traits::to2D(cur_ll.centerline()[p_idx]));
266 dist += lanelet::geometry::distance2d(prev_point, previous_lane.back());
268 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"distance " << dist);
269 prev_point = lanelet::traits::to2D(cur_ll.centerline()[p_idx]);
272 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"Adding lane with size: " << previous_lane.size());
273 reverse_lanes->emplace_back(previous_lane);
279 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"In composeTrafficControlMesssages");
282 RCLCPP_WARN_STREAM(
logger_->get_logger(),
"Traffic Incident Parser is composing a Traffic Control Message, but it has not loaded the map yet. Returning empty list");
287 RCLCPP_WARN_STREAM(
logger_->get_logger(),
"Traffic Incident Parser is composing a Traffic Control Message, but georeference has not loaded yet. Returning empty list");
292 auto current_lanelets = lanelet::geometry::findNearest(
wm_->getMap()->laneletLayer,
local_point_, 1);
293 if (current_lanelets.empty()) {
298 lanelet::ConstLanelet current_lanelet = current_lanelets[0].second;
300 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"Nearest Lanelet: " << current_lanelet.id());
302 lanelet::ConstLanelets lefts = { current_lanelet };
303 for (
const auto& l :
wm_->getMapRoutingGraph()->lefts(current_lanelet)) {
304 lefts.emplace_back(l);
305 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"Left lanelet: " << l.id());
308 lanelet::ConstLanelets rights =
wm_->getMapRoutingGraph()->rights(current_lanelet);
309 for (
const auto& l : rights) {
310 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"Right lanelet: " << l.id());
314 std::vector<std::vector<lanelet::BasicPoint2d>> forward_lanes;
315 std::vector<std::vector<lanelet::BasicPoint2d>> reverse_lanes;
317 if (lefts.size() >= rights.size()) {
318 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"Emergency vehicle on the right ");
322 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"Emergency vehicle on the left ");
327 for (
auto& lane : reverse_lanes) {
328 std::reverse(lane.begin(), lane.end());
332 for (
size_t i = 0;
i < reverse_lanes.size();
i++) {
333 if (forward_lanes[
i].size() > 1) {
334 reverse_lanes[
i].insert(reverse_lanes[
i].end(), forward_lanes[
i].begin() + 1, forward_lanes[
i].end());
338 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"Constructing message for lanes: " << reverse_lanes.size());
339 std::vector<carma_v2x_msgs::msg::TrafficControlMessageV01> output_msg;
341 carma_v2x_msgs::msg::TrafficControlMessageV01 traffic_mobility_msg;
343 traffic_mobility_msg.geometry_exists=
true;
344 traffic_mobility_msg.params_exists=
true;
345 traffic_mobility_msg.package_exists=
true;
346 j2735_v2x_msgs::msg::TrafficControlVehClass veh_type;
347 veh_type.vehicle_class = j2735_v2x_msgs::msg::TrafficControlVehClass::ANY;
348 traffic_mobility_msg.params.vclasses.push_back(veh_type);
349 traffic_mobility_msg.params.schedule.start=
clock_->now();
350 traffic_mobility_msg.params.schedule.end_exists=
false;
351 traffic_mobility_msg.params.schedule.dow_exists=
false;
352 traffic_mobility_msg.params.schedule.between_exists=
false;
353 traffic_mobility_msg.params.schedule.repeat_exists =
false;
360 std::string common_frame =
"WGS84";
362 PJ* common_to_map_proj = proj_create_crs_to_crs(PJ_DEFAULT_CTX, common_frame.c_str(),
projection_msg_.c_str() ,
nullptr);
364 if (common_to_map_proj ==
nullptr) {
366 RCLCPP_ERROR_STREAM(
logger_->get_logger(),
"Failed to generate projection between map georeference and common frame with error number: " << proj_context_errno(PJ_DEFAULT_CTX)
367 <<
" projection_msg_: " <<
projection_msg_ <<
" common_frame: " << common_frame);
372 PJ_COORD map_origin_map_frame{{0.0, 0.0, 0.0, 0.0}};
373 PJ_COORD map_origin_in_common_frame;
375 map_origin_in_common_frame = proj_trans(common_to_map_proj, PJ_INV, map_origin_map_frame);
377 traffic_mobility_msg.geometry.datum =
"WGS84";
378 traffic_mobility_msg.geometry.reflat = map_origin_in_common_frame.lpz.lam;
379 traffic_mobility_msg.geometry.reflon = map_origin_in_common_frame.lpz.phi;
381 std::ostringstream lat_string;
382 std::ostringstream lon_string;
384 lat_string.precision(14);
385 lat_string << std::fixed << traffic_mobility_msg.geometry.reflat;
387 lon_string.precision(14);
388 lon_string << std::fixed << traffic_mobility_msg.geometry.reflon;
392 std::string local_tmerc_enu_proj =
"+proj=tmerc +datum=WGS84 +h_0=0 +lat_0=" + lat_string.str() +
" +lon_0=" + lon_string.str() +
" +k=1 +x_0=0 +y_0=0 +units=m +vunits=m +no_defs";
394 PJ* map_to_tmerc_proj = proj_create_crs_to_crs(PJ_DEFAULT_CTX,
projection_msg_.c_str(), local_tmerc_enu_proj.c_str() ,
nullptr);
396 if (map_to_tmerc_proj ==
nullptr) {
398 RCLCPP_ERROR_STREAM(
logger_->get_logger(),
"Failed to generate projection between map georeference and tmerc frame with error number: " << proj_context_errno(PJ_DEFAULT_CTX)
399 <<
" projection_msg_: " <<
projection_msg_ <<
" local_tmerc_enu_proj: " << local_tmerc_enu_proj);
404 traffic_mobility_msg.geometry.proj = local_tmerc_enu_proj;
406 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"Projection in message: " << traffic_mobility_msg.geometry.proj);
412 for (
size_t i = 0;
i < reverse_lanes.size();
i++) {
414 traffic_mobility_msg.geometry.nodes.clear();
415 if (reverse_lanes[
i].size() == 0) {
416 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"Skipping empty lane");
421 PJ_COORD map_pt{{reverse_lanes[
i].front().x(), reverse_lanes[
i].front().y(), 0.0, 0.0}};
423 PJ_COORD tmerc_pt = proj_trans(map_to_tmerc_proj, PJ_FWD, map_pt);
425 carma_v2x_msgs::msg::PathNode prev_point;
426 prev_point.x = tmerc_pt.xyz.x;
427 prev_point.y = tmerc_pt.xyz.y;
429 for(
const auto& p : carma_ros2_utils::containers::downsample_vector(reverse_lanes[
i], 8))
431 carma_v2x_msgs::msg::PathNode delta;
433 map_pt = PJ_COORD({p.x(), p.y(), 0.0, 0.0});
434 tmerc_pt = proj_trans(map_to_tmerc_proj, PJ_FWD, map_pt);
436 delta.x=tmerc_pt.xyz.x - prev_point.x;
437 delta.y=tmerc_pt.xyz.y - prev_point.y;
439 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"prev_point x" << prev_point.x <<
", prev_point y " << prev_point.y);
440 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"tmerc_pt.xyz.x" << tmerc_pt.xyz.x <<
", tmerc_pt.xyz.y " << tmerc_pt.xyz.y);
441 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"map_pt x" << p.x() <<
", map_pt y " << p.y());
443 RCLCPP_DEBUG_STREAM(
logger_->get_logger(),
"calculated diff x" << delta.x <<
", diff y" << delta.y);
446 traffic_mobility_msg.geometry.nodes.push_back(prev_point);
451 traffic_mobility_msg.geometry.nodes.push_back(delta);
454 prev_point.x = p.x();
455 prev_point.y = p.y();
459 boost::uuids::uuid closure_id = boost::uuids::random_generator()();
460 std::copy(closure_id.begin(), closure_id.end(), traffic_mobility_msg.id.id.begin());
461 traffic_mobility_msg.params.detail.choice=carma_v2x_msgs::msg::TrafficControlDetail::CLOSED_CHOICE;
462 traffic_mobility_msg.params.detail.closed=carma_v2x_msgs::msg::TrafficControlDetail::CLOSED;
464 output_msg.push_back(traffic_mobility_msg);
467 boost::uuids::uuid headway_id = boost::uuids::random_generator()();
468 std::copy(headway_id.begin(), headway_id.end(), traffic_mobility_msg.id.id.begin());
469 traffic_mobility_msg.params.detail.choice=carma_v2x_msgs::msg::TrafficControlDetail::MINHDWY_CHOICE;
470 traffic_mobility_msg.params.detail.minhdwy=
min_gap;
471 output_msg.push_back(traffic_mobility_msg);
473 boost::uuids::uuid speed_id = boost::uuids::random_generator()();
474 std::copy(speed_id.begin(), speed_id.end(), traffic_mobility_msg.id.id.begin());
475 traffic_mobility_msg.params.detail.choice=carma_v2x_msgs::msg::TrafficControlDetail::MAXSPEED_CHOICE;
477 output_msg.push_back(traffic_mobility_msg);
std::function< void(const carma_v2x_msgs::msg::TrafficControlMessage &)> PublishTrafficControlCallback
carma_wm::WorldModelConstPtr wm_
std::string stringParserHelper(std::string str, unsigned long str_index) const
Function to help convert string to double data type.
std::string previous_strategy_params
TrafficIncidentParserWorker(carma_wm::WorldModelConstPtr wm, const PublishTrafficControlCallback &traffic_control_pub, rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr logger, rclcpp::Clock::SharedPtr clock)
TrafficIncidentParserWorker constructor.
lanelet::BasicPoint2d getIncidentOriginPoint() const
Function to convert internally saved incident origin point from lat/lon to local map frame.
PublishTrafficControlCallback traffic_control_pub_
std::string projection_msg_
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr logger_
std::vector< carma_v2x_msgs::msg::TrafficControlMessageV01 > composeTrafficControlMesssages()
Algorithm for extracting the closed lanelet from internally saved mobility message (or geofence) para...
bool mobilityMessageParser(std::string mobility_strategy_params)
Function to help parse incoming mobility operation messages to required format.
void georeferenceCallback(std_msgs::msg::String::UniquePtr projection_msg)
Callback for the georeference subscriber used to set the map projection.
void getAdjacentForwardCenterlines(const lanelet::ConstLanelets &adjacentSet, const lanelet::BasicPoint2d &start_point, double downtrack, std::vector< std::vector< lanelet::BasicPoint2d > > *forward_lanes) const
Helper method to compute the concatenated centerlines of the lanes in front of the emergency vehicle ...
void mobilityOperationCallback(carma_v2x_msgs::msg::MobilityOperation::UniquePtr mobility_msg)
Function to receive the incoming mobility operation message from the message node and publish the geo...
rclcpp::Clock::SharedPtr clock_
void getAdjacentReverseCenterlines(const lanelet::ConstLanelets &adjacentSet, const lanelet::BasicPoint2d &start_point, double uptrack, std::vector< std::vector< lanelet::BasicPoint2d > > *reverse_lanes) const
Helper method that is identical to getAdjacentForwardCenterlines except it works in reverse using upt...
lanelet::BasicPoint2d local_point_
std::shared_ptr< const WorldModel > WorldModelConstPtr
size_t getNearestPointIndex(const lanelet::ConstLineString3d &points, const lanelet::BasicPoint2d &point)
Helper method to get the nearest point index of a point and a linestring.