Carma-platform v4.10.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.
traffic_incident_parser_worker.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2020-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
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>
24#include <proj.h>
25
27{
29 rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr logger, rclcpp::Clock::SharedPtr clock)
30 : traffic_control_pub_(traffic_control_pub), wm_(wm), logger_(logger), clock_(clock) {}
31
32 void TrafficIncidentParserWorker::mobilityOperationCallback(carma_v2x_msgs::msg::MobilityOperation::UniquePtr mobility_msg)
33 {
34 if(!wm_->getMap())
35 {
36 RCLCPP_WARN_STREAM(logger_->get_logger(), "The map is not loaded yet, ignoring the Traffic Incident Mobility Message");
37 return;
38 }
39 if (projection_msg_ == "")
40 {
41 RCLCPP_WARN_STREAM(logger_->get_logger(), "The georeference is not loaded yet, ignoring the Traffic Incident Mobility Message");
42 return;
43 }
44 if(!wm_->getRoute())
45 {
46 RCLCPP_WARN_STREAM(logger_->get_logger(), "The route is not loaded yet, ignoring the Traffic Incident Mobility Message");
47 return;
48 }
49
50 if(mobility_msg->strategy=="carma3/Incident_Use_Case")
51 {
52
53 bool valid_msg = mobilityMessageParser(mobility_msg->strategy_params);
54
55 if(valid_msg && event_type=="CLOSED")
56 {
57 previous_strategy_params=mobility_msg->strategy_params;
58 carma_v2x_msgs::msg::TrafficControlMessage traffic_control_msg;
59 traffic_control_msg.choice = carma_v2x_msgs::msg::TrafficControlMessage::TCMV01;
60 for(const auto &traffic_msg : composeTrafficControlMesssages())
61 {
62 traffic_control_msg.tcm_v01=traffic_msg;
63 traffic_control_pub_(traffic_control_msg); // Publish the message to existing subscribers
64 }
65 }
66 else
67 {
68 return;
69 }
70 }
71 }
72
73 void TrafficIncidentParserWorker::georeferenceCallback(std_msgs::msg::String::UniquePtr projection_msg)
74 {
75 projection_msg_=projection_msg->data;
76 }
77
78
79 bool TrafficIncidentParserWorker::mobilityMessageParser(std::string mobility_strategy_params)
80 {
81
82 std::vector<std::string> vec={};
83 std::string delimiter = ",";
84 size_t pos = 0;
85 std::string token;
86 while ((pos = mobility_strategy_params.find(delimiter)) != std::string::npos)
87 {
88 token = mobility_strategy_params.substr(0, pos);
89 vec.push_back(token);
90 mobility_strategy_params.erase(0, pos + delimiter.length());
91 }
92 vec.push_back(mobility_strategy_params);
93
94 if (vec.size() != 8)
95 {
96 RCLCPP_ERROR_STREAM(logger_->get_logger(),"Given mobility strategy params are not correctly formatted.");
97 return false;
98 }
99
100 std::string lat_str=vec[0];
101 std::string lon_str=vec[1];
102 std::string downtrack_str=vec[2];
103 std::string uptrack_str=vec[3];
104 std::string min_gap_str=vec[4];
105 std::string speed_advisory_str=vec[5];
106 std::string event_reason_str=vec[6];
107 std::string event_type_str=vec[7];
108
109 // Evaluate if this message should be forwarded based on the gps point
110 double temp_lat = stod(stringParserHelper(lat_str,lat_str.find_last_of("lat:")));
111 double temp_lon = stod(stringParserHelper(lon_str,lon_str.find_last_of("lon:")));
112
113 double constexpr APPROXIMATE_DEG_PER_5M = 0.00005;
114 double delta_lat = temp_lat - latitude;
115 double delta_lon = temp_lon - longitude;
116 double approximate_degree_delta = sqrt(delta_lat*delta_lat + delta_lon*delta_lon);
117
118 double temp_down_track=stod(stringParserHelper(downtrack_str,downtrack_str.find_last_of("down_track:")));
119 double temp_up_track=stod(stringParserHelper(uptrack_str,uptrack_str.find_last_of("up_track:")));
120 double temp_min_gap=stod(stringParserHelper(min_gap_str,min_gap_str.find_last_of("min_gap:")));
121 double temp_speed_advisory=stod(stringParserHelper(speed_advisory_str,speed_advisory_str.find_last_of("advisory_speed:"))) * MphToMetersPerSec;
122 std::string temp_event_reason=stringParserHelper(event_reason_str,event_reason_str.find_last_of("event_reason:"));
123 std::string temp_event_type=stringParserHelper(event_type_str,event_type_str.find_last_of("event_type:"));
124
125 if ( approximate_degree_delta < APPROXIMATE_DEG_PER_5M // If the vehicle has not moved more than 5m and the parameters remain unchanged
126 && temp_down_track == down_track
127 && temp_up_track == up_track
128 && temp_min_gap == min_gap
129 && temp_speed_advisory == speed_advisory
130 && temp_event_reason == event_reason
131 && temp_event_type == event_type) {
132
133 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "Strategy params are unchanged so ignoring new message: " << mobility_strategy_params
134 << " degree_delta: " << approximate_degree_delta
135 << " prev_lat: " << latitude << " prev_lon: " << longitude);
136
137 return false;
138
139 }
140
141 // Valid message contents so populate member variables
142 latitude = temp_lat;
143 longitude = temp_lon;
144 down_track = temp_down_track;
145 up_track = temp_up_track;
146 min_gap = temp_min_gap;
147 speed_advisory = temp_speed_advisory;
148 event_reason = temp_event_reason;
149 event_type = temp_event_type;
150
151 return true;
152 }
153
154 std::string TrafficIncidentParserWorker::stringParserHelper(std::string str, unsigned long str_index) const
155 {
156 std::string str_temp="";
157 for(size_t i=str_index+1;i<str.length();i++)
158 {
159 str_temp+=str[i];
160 }
161 return str_temp;
162 }
163
165 {
166 lanelet::projection::LocalFrameProjector projector(projection_msg_.c_str());
167 lanelet::GPSPoint gps_point;
168 gps_point.lat = latitude;
169 gps_point.lon = longitude;
170 gps_point.ele = 0;
171 auto local_point3d = projector.forward(gps_point);
172 return {local_point3d.x(), local_point3d.y()};
173 }
174
178 size_t getNearestPointIndex(const lanelet::ConstLineString3d& points,
179 const lanelet::BasicPoint2d& point)
180 {
181 double min_distance = std::numeric_limits<double>::max();
182 size_t i = 0;
183 size_t best_index = 0;
184 for (const auto& p : points)
185 {
186 double distance = lanelet::geometry::distance2d(p, point);
187 if (distance < min_distance)
188 {
189 best_index = i;
190 min_distance = distance;
191 }
192 i++;
193 }
194
195 return best_index;
196 }
197
198 void TrafficIncidentParserWorker::getAdjacentForwardCenterlines(const lanelet::ConstLanelets& adjacentSet,
199 const lanelet::BasicPoint2d& start_point, double downtrack, std::vector<std::vector<lanelet::BasicPoint2d>>* forward_lanes) const
200 {
201 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "getAdjacentForwardCenterlines");
202 for (const auto& ll : adjacentSet) {
203 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "Processing adjacent lanelet: " << ll.id());
204 std::vector<lanelet::BasicPoint2d> following_lane;
205 auto cur_ll = ll;
206 double dist = 0;
207
208
209 // Identify the point to start the accumulation from
210 size_t p_idx = getNearestPointIndex(cur_ll.centerline(), start_point); // Get the index of the nearest point
211
212 lanelet::BasicPoint2d prev_point = cur_ll.centerline()[p_idx].basicPoint2d();
213
214 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "nearest point" << cur_ll.centerline()[p_idx].id() << " : " << prev_point.x() << ", " << prev_point.y());
215
216 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "p_idx: " << p_idx);
217
218 // Accumulate distance
219 while (dist < downtrack) {
220 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "Accumulating lanelet: " << cur_ll.id());
221 if (p_idx == cur_ll.centerline().size()) {
222 auto next_lls = wm_->getMapRoutingGraph()->following(cur_ll, false);
223 if (next_lls.empty()) {
224 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "No followers");
225 break;
226 }
227 const auto& next = next_lls[0];
228 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "Getting next lanelet: " << next.id());
229 cur_ll = next;
230 p_idx = 0;
231 }
232 if (p_idx != 0 || dist == 0) {
233 following_lane.push_back(lanelet::traits::to2D(cur_ll.centerline()[p_idx]));
234 dist += lanelet::geometry::distance2d(prev_point, following_lane.back());
235 }
236 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "distance " << dist);
237 prev_point = lanelet::traits::to2D(cur_ll.centerline()[p_idx]);
238 p_idx++;
239 }
240 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "Adding lane with size: " << following_lane.size());
241 forward_lanes->emplace_back(following_lane);
242 }
243 }
244
245 void TrafficIncidentParserWorker::getAdjacentReverseCenterlines(const lanelet::ConstLanelets& adjacentSet,
246 const lanelet::BasicPoint2d& start_point, double uptrack, std::vector<std::vector<lanelet::BasicPoint2d>>* reverse_lanes) const
247 {
248 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "getAdjacentReverseCenterlines");
249 for (const auto& ll : adjacentSet) {
250 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "Processing adjacent lanelet: " << ll.id());
251 std::vector<lanelet::BasicPoint2d> previous_lane;
252 auto cur_ll = ll;
253 double dist = 0;
254
255 // Identify the point to start the accumulation from
256 size_t p_idx = getNearestPointIndex(cur_ll.centerline(), start_point); // Get the index of the nearest point
257
258 lanelet::BasicPoint2d prev_point = cur_ll.centerline()[p_idx].basicPoint2d();
259
260 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "nearest point" << cur_ll.centerline()[p_idx].id() << " : " << prev_point.x() << ", " << prev_point.y());
261
262 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "p_idx: " << p_idx);
263
264 // Accumulate distance
265 while (dist < uptrack) {
266 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "Accumulating lanelet: " << cur_ll.id());
267 if (p_idx == 0) {
268 auto next_lls = wm_->getMapRoutingGraph()->previous(cur_ll, false);
269 if (next_lls.empty()) {
270 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "No previous lanelets");
271 break;
272 }
273 const auto& next = next_lls[0];
274 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "Getting next lanelet: " << next.id());
275 cur_ll = next;
276 p_idx = cur_ll.centerline().size() - 1;
277 }
278 if (p_idx != cur_ll.centerline().size() - 1 || dist == 0) {
279
280 previous_lane.push_back(lanelet::traits::to2D(cur_ll.centerline()[p_idx]));
281 dist += lanelet::geometry::distance2d(prev_point, previous_lane.back());
282 }
283 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "distance " << dist);
284 prev_point = lanelet::traits::to2D(cur_ll.centerline()[p_idx]);
285 p_idx--;
286 }
287 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "Adding lane with size: " << previous_lane.size());
288 reverse_lanes->emplace_back(previous_lane);
289 }
290 }
291
292 std::vector<carma_v2x_msgs::msg::TrafficControlMessageV01> TrafficIncidentParserWorker::composeTrafficControlMesssages()
293 {
294 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "In composeTrafficControlMesssages");
295
297 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "Responder point in map frame: " << local_point_.x() << ", " << local_point_.y());
298 auto current_lanelets = lanelet::geometry::findNearest(wm_->getMap()->laneletLayer, local_point_, 1);
299 if (current_lanelets.empty()) {
300 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "No nearest lanelet to responder vehicle in map point: " << local_point_.x() << ", " << local_point_.y());
301 return {};
302 }
303
304 lanelet::ConstLanelet current_lanelet = current_lanelets[0].second;
305
306 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "Nearest Lanelet: " << current_lanelet.id());
307
308 lanelet::ConstLanelets lefts = { current_lanelet };
309 for (const auto& l : wm_->getMapRoutingGraph()->lefts(current_lanelet)) {
310 lefts.emplace_back(l);
311 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "Left lanelet: " << l.id());
312 }
313
314 lanelet::ConstLanelets rights = wm_->getMapRoutingGraph()->rights(current_lanelet);
315 for (const auto& l : rights) {
316 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "Right lanelet: " << l.id());
317 }
318
319 // Assume that if there are more lanelets to the left than the right then the tahoe is on the left
320 std::vector<std::vector<lanelet::BasicPoint2d>> forward_lanes;
321 std::vector<std::vector<lanelet::BasicPoint2d>> reverse_lanes;
322
323 if (lefts.size() >= rights.size()) {
324 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "Emergency vehicle on the right ");
326 getAdjacentReverseCenterlines(lefts, local_point_, up_track, &reverse_lanes);
327 } else {
328 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "Emergency vehicle on the left ");
329 getAdjacentForwardCenterlines(rights, local_point_, down_track, &forward_lanes);
330 getAdjacentReverseCenterlines(rights, local_point_, up_track, &reverse_lanes);
331 }
332
333 for (auto& lane : reverse_lanes) {
334 std::reverse(lane.begin(), lane.end()); // Reverse the backward points
335 }
336
337 // Compine results
338 for (size_t i = 0; i < reverse_lanes.size(); i++) {
339 if (forward_lanes[i].size() > 1) {
340 reverse_lanes[i].insert(reverse_lanes[i].end(), forward_lanes[i].begin() + 1, forward_lanes[i].end()); // Concat linestirngs but drop the shared point
341 }
342 }
343
344 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "Constructing message for lanes: " << reverse_lanes.size());
345 std::vector<carma_v2x_msgs::msg::TrafficControlMessageV01> output_msg;
346
347 carma_v2x_msgs::msg::TrafficControlMessageV01 traffic_mobility_msg;
348
349 traffic_mobility_msg.geometry_exists=true;
350 traffic_mobility_msg.params_exists=true;
351 traffic_mobility_msg.package_exists=true;
352 j2735_v2x_msgs::msg::TrafficControlVehClass veh_type;
353 veh_type.vehicle_class = j2735_v2x_msgs::msg::TrafficControlVehClass::ANY; // TODO decide what vehicle is affected
354 traffic_mobility_msg.params.vclasses.push_back(veh_type);
355 traffic_mobility_msg.params.schedule.start=clock_->now();
356 traffic_mobility_msg.params.schedule.end_exists=false;
357 traffic_mobility_msg.params.schedule.dow_exists=false;
358 traffic_mobility_msg.params.schedule.between_exists=false;
359 traffic_mobility_msg.params.schedule.repeat_exists = false;
360
362 // Begin handling of projection definition
363 // This logic works by enforcing the ROS2 message specifications for TrafficControlMessage on the output data
364 // First the latlon point in the provided data is identified, then a projection with a north east oriented tmerc frame is created to compute node locations
366 std::string common_frame = "WGS84"; // Common frame to use for lat/lon definition. This will populate the datum field of the message. A more complex CRS should not be used here
367
368 PJ* common_to_map_proj = proj_create_crs_to_crs(PJ_DEFAULT_CTX, common_frame.c_str(), projection_msg_.c_str() , nullptr); // Create transformation between map frame and common frame. Reverse here takes map->latlon. Froward is latlon->map
369
370 if (common_to_map_proj == nullptr) { // proj_create_crs_to_crs returns 0 when there is an error in the projection
371
372 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)
373 << " projection_msg_: " << projection_msg_ << " common_frame: " << common_frame);
374
375 return {}; // Ignore geofence if it could not be projected into the map frame
376 }
377
378 PJ_COORD map_origin_map_frame{{0.0, 0.0, 0.0, 0.0}}; // Map origin to use as ref lat/lon
379 PJ_COORD map_origin_in_common_frame;
380
381 map_origin_in_common_frame = proj_trans(common_to_map_proj, PJ_INV, map_origin_map_frame);
382
383 traffic_mobility_msg.geometry.datum = "WGS84";
384 traffic_mobility_msg.geometry.reflat = map_origin_in_common_frame.lpz.lam;
385 traffic_mobility_msg.geometry.reflon = map_origin_in_common_frame.lpz.phi;
386
387 std::ostringstream lat_string;
388 std::ostringstream lon_string;
389
390 lat_string.precision(14);
391 lat_string << std::fixed << traffic_mobility_msg.geometry.reflat;
392
393 lon_string.precision(14);
394 lon_string << std::fixed << traffic_mobility_msg.geometry.reflon;
395
396 // Create a local transverse mercator frame at the reference point to allow us to get east,north oriented data reguardless of map projection orientation
397 // This is needed to match the TrafficControlMessage specification
398 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";
399
400 PJ* map_to_tmerc_proj = proj_create_crs_to_crs(PJ_DEFAULT_CTX, projection_msg_.c_str(), local_tmerc_enu_proj.c_str() , nullptr); // Create transformation between the common frame and the local ENU oriented frame
401
402 if (map_to_tmerc_proj == nullptr) { // proj_create_crs_to_crs returns 0 when there is an error in the projection
403
404 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)
405 << " projection_msg_: " << projection_msg_ << " local_tmerc_enu_proj: " << local_tmerc_enu_proj);
406
407 return {}; // Ignore geofence if it could not be projected into the map frame
408 }
409
410 traffic_mobility_msg.geometry.proj = local_tmerc_enu_proj;
411
412 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "Projection in message: " << traffic_mobility_msg.geometry.proj);
413
415 // Projections setup. Next projections will be used for node computation
417
418 for (size_t i = 0; i < reverse_lanes.size(); i++) {
419
420 traffic_mobility_msg.geometry.nodes.clear();
421 if (reverse_lanes[i].size() == 0) {
422 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "Skipping empty lane");
423 continue;
424 }
425
426
427 PJ_COORD map_pt{{reverse_lanes[i].front().x(), reverse_lanes[i].front().y(), 0.0, 0.0}}; // Map point to convert to tmerc frame
428
429 PJ_COORD tmerc_pt = proj_trans(map_to_tmerc_proj, PJ_FWD, map_pt);
430
431 carma_v2x_msgs::msg::PathNode prev_point;
432 prev_point.x = tmerc_pt.xyz.x;
433 prev_point.y = tmerc_pt.xyz.y;
434 bool first = true;
435 for(const auto& p : carma_ros2_utils::containers::downsample_vector(reverse_lanes[i], 8))
436 {
437 carma_v2x_msgs::msg::PathNode delta;
438
439 map_pt = PJ_COORD({p.x(), p.y(), 0.0, 0.0}); // Map point to convert to tmerc frame
440 tmerc_pt = proj_trans(map_to_tmerc_proj, PJ_FWD, map_pt); // Convert point to tmerc frame
441
442 delta.x=tmerc_pt.xyz.x - prev_point.x;
443 delta.y=tmerc_pt.xyz.y - prev_point.y;
444
445 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "prev_point x" << prev_point.x << ", prev_point y " << prev_point.y);
446 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "tmerc_pt.xyz.x" << tmerc_pt.xyz.x << ", tmerc_pt.xyz.y " << tmerc_pt.xyz.y);
447 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "map_pt x" << p.x() << ", map_pt y " << p.y());
448
449 RCLCPP_DEBUG_STREAM(logger_->get_logger(), "calculated diff x" << delta.x << ", diff y" << delta.y);
450 if (first)
451 {
452 traffic_mobility_msg.geometry.nodes.push_back(prev_point);
453 first = false;
454 }
455 else
456 {
457 traffic_mobility_msg.geometry.nodes.push_back(delta);
458 }
459
460 prev_point.x = p.x();
461 prev_point.y = p.y();
462 }
463
464 if (i == 0) {
465 boost::uuids::uuid closure_id = boost::uuids::random_generator()();
466 std::copy(closure_id.begin(), closure_id.end(), traffic_mobility_msg.id.id.begin());
467 traffic_mobility_msg.params.detail.choice=carma_v2x_msgs::msg::TrafficControlDetail::CLOSED_CHOICE;
468 traffic_mobility_msg.params.detail.closed=carma_v2x_msgs::msg::TrafficControlDetail::CLOSED;
469 traffic_mobility_msg.package.label=event_reason;
470 output_msg.push_back(traffic_mobility_msg);
471 }
472
473 boost::uuids::uuid headway_id = boost::uuids::random_generator()();
474 std::copy(headway_id.begin(), headway_id.end(), traffic_mobility_msg.id.id.begin());
475 traffic_mobility_msg.params.detail.choice=carma_v2x_msgs::msg::TrafficControlDetail::MINHDWY_CHOICE;
476 traffic_mobility_msg.params.detail.minhdwy=min_gap;
477 output_msg.push_back(traffic_mobility_msg);
478
479 boost::uuids::uuid speed_id = boost::uuids::random_generator()();
480 std::copy(speed_id.begin(), speed_id.end(), traffic_mobility_msg.id.id.begin());
481 traffic_mobility_msg.params.detail.choice=carma_v2x_msgs::msg::TrafficControlDetail::MAXSPEED_CHOICE;
482 traffic_mobility_msg.params.detail.maxspeed=speed_advisory;
483 output_msg.push_back(traffic_mobility_msg);
484
485 }
486
487
488 return output_msg;
489
490 }
491
492} // traffic_incident_parser
std::function< void(const carma_v2x_msgs::msg::TrafficControlMessage &)> PublishTrafficControlCallback
std::string stringParserHelper(std::string str, unsigned long str_index) const
Function to help convert string to double data type.
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.
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...
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...
std::shared_ptr< const WorldModel > WorldModelConstPtr
Definition: WorldModel.hpp:454
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.