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.
carma_wm::WMListenerWorker Class Reference

Backend logic class for WMListener. More...

#include <WMListenerWorker.hpp>

Collaboration diagram for carma_wm::WMListenerWorker:
Collaboration graph

Public Member Functions

 WMListenerWorker (rclcpp::Logger logger=rclcpp::get_logger("carma_wm"))
 Constructor. More...
 
WorldModelConstPtr getWorldModel () const
 Constructor. More...
 
void mapCallback (const autoware_lanelet2_msgs::msg::MapBin::SharedPtr map_msg)
 Callback for new map messages. Updates the underlying map. More...
 
void mapUpdateCallback (autoware_lanelet2_msgs::msg::MapBin::SharedPtr geofence_msg)
 Callback for new map update messages (geofence). Updates the underlying map. More...
 
void routeCallback (const carma_planning_msgs::msg::Route::SharedPtr route_msg)
 Callback for route message. More...
 
void ros1ClockCallback (const rosgraph_msgs::msg::Clock::SharedPtr clock_msg)
 Callback for ROS1 clock message (used in Simulation runs) More...
 
void simClockCallback (const rosgraph_msgs::msg::Clock::SharedPtr clock_msg)
 Callback for Simulation clock message (used in Simulation runs) More...
 
void roadwayObjectListCallback (const carma_perception_msgs::msg::RoadwayObstacleList::SharedPtr msg)
 Callback for roadway objects msg. More...
 
void setMapCallback (std::function< void()> callback)
 Allows user to set a callback to be triggered when a map update is received. More...
 
void setRouteCallback (std::function< void()> callback)
 Allows user to set a callback to be triggered when a route update is received. More...
 
void setConfigSpeedLimit (double config_lim)
 Allows user to set a callback to be triggered when a map update is received. More...
 
double getConfigSpeedLimit () const
 Returns the current configured speed limit value. More...
 
void setVehicleParticipationType (std::string participant)
 Allows user to set a callback to be triggered when a map update is received. More...
 
std::string getVehicleParticipationType () const
 Returns the Vehicle Participation Type value. More...
 
bool checkIfReRoutingNeeded () const
 Check if re-routing is needed and returns re-routing flag. More...
 
void enableUpdatesWithoutRoute ()
 Enable updates without route and set route_node_flag_ as true. More...
 
LaneletRoutingGraphPtr routingGraphFromMsg (const autoware_lanelet2_msgs::msg::RoutingGraph &msg, lanelet::LaneletMapPtr map) const
 Helper function to convert a routing graph message into a actual RoutingGraph object. More...
 
void incomingSpatCallback (const carma_v2x_msgs::msg::SPAT::SharedPtr spat_msg)
 incoming spat message More...
 
void isUsingSimTime (bool use_sim_time) const
 set true if simulation_mode is on More...
 
void isSpatWallTime (bool use_real_time_spat_in_sim) const
 set true if incoming spat is based on wall clock More...
 
void setWMSpatProcessingState (const SIGNAL_PHASE_PROCESSING &phase_type) const
 Activate World Model SPAT processor, which is turned off by default, with OFF (0), ON (1), FIXED (2) More...
 
SIGNAL_PHASE_PROCESSING getWMSpatProcessingState () const
 Get World Model SPAT processor state from signalized intersection manager. More...
 

Private Member Functions

void newRegemUpdateHelper (lanelet::Lanelet parent_llt, lanelet::RegulatoryElement *regem) const
 This is a helper function updates the parent_llt with specified regem. This function is needed as we need to dynamic_cast from general regem to specific type of regem based on the geofence. More...
 

Private Attributes

rclcpp::Logger logger_
 
std::shared_ptr< CARMAWorldModelworld_model_
 
std::function< void()> map_callback_
 
std::function< void()> route_callback_
 
double config_speed_limit_
 
size_t current_map_version_ = 0
 
std::queue< autoware_lanelet2_msgs::msg::MapBin::SharedPtr > map_update_queue_
 
boost::optional< carma_planning_msgs::msg::Route > delayed_route_msg_
 
bool recompute_route_flag_ =false
 
bool rerouting_flag_ =false
 
bool route_node_flag_ =false
 
long most_recent_update_msg_seq_ = -1
 

Detailed Description

Backend logic class for WMListener.

Definition at line 35 of file WMListenerWorker.hpp.

Constructor & Destructor Documentation

◆ WMListenerWorker()

carma_wm::WMListenerWorker::WMListenerWorker ( rclcpp::Logger  logger = rclcpp::get_logger("carma_wm"))
explicit

Constructor.

Parameters
loggerLogger to use for all log output. Pass the calling node's get_child("carma_wm") logger so messages appear in MCAP. Defaults to a standalone logger for backward compatibility.

Definition at line 45 of file WMListenerWorker.cpp.

46: logger_(logger)
47{
48 world_model_.reset(new CARMAWorldModel);
49}
std::shared_ptr< CARMAWorldModel > world_model_

References world_model_.

Member Function Documentation

◆ checkIfReRoutingNeeded()

bool carma_wm::WMListenerWorker::checkIfReRoutingNeeded ( ) const

Check if re-routing is needed and returns re-routing flag.

Definition at line 110 of file WMListenerWorker.cpp.

111{
112 return rerouting_flag_;
113}

References rerouting_flag_.

◆ enableUpdatesWithoutRoute()

void carma_wm::WMListenerWorker::enableUpdatesWithoutRoute ( )

Enable updates without route and set route_node_flag_ as true.

Definition at line 115 of file WMListenerWorker.cpp.

116{
117 route_node_flag_=true;
118}

References route_node_flag_.

◆ getConfigSpeedLimit()

double carma_wm::WMListenerWorker::getConfigSpeedLimit ( ) const

Returns the current configured speed limit value.

Definition at line 725 of file WMListenerWorker.cpp.

726{
727 return config_speed_limit_;
728}

References config_speed_limit_.

◆ getVehicleParticipationType()

std::string carma_wm::WMListenerWorker::getVehicleParticipationType ( ) const

Returns the Vehicle Participation Type value.

Definition at line 569 of file WMListenerWorker.cpp.

570{
571 return world_model_->getVehicleParticipationType();
572}

References world_model_.

Referenced by routingGraphFromMsg().

Here is the caller graph for this function:

◆ getWMSpatProcessingState()

SIGNAL_PHASE_PROCESSING carma_wm::WMListenerWorker::getWMSpatProcessingState ( ) const

Get World Model SPAT processor state from signalized intersection manager.

Returns
World Model SPAT process state OFF (0), ON(1)

Definition at line 720 of file WMListenerWorker.cpp.

721{
722 return world_model_->sim_.spat_processor_state_;
723}

References world_model_.

◆ getWorldModel()

WorldModelConstPtr carma_wm::WMListenerWorker::getWorldModel ( ) const

Constructor.

Definition at line 51 of file WMListenerWorker.cpp.

52{
53 return std::static_pointer_cast<const WorldModel>(world_model_); // Cast pointer to const variant
54}

References world_model_.

◆ incomingSpatCallback()

void carma_wm::WMListenerWorker::incomingSpatCallback ( const carma_v2x_msgs::msg::SPAT::SharedPtr  spat_msg)

incoming spat message

Definition at line 105 of file WMListenerWorker.cpp.

106{
107 world_model_->sim_.processSpatFromMsg(*spat_msg, world_model_->getMutableMap());
108}

References world_model_.

◆ isSpatWallTime()

void carma_wm::WMListenerWorker::isSpatWallTime ( bool  use_real_time_spat_in_sim) const

set true if incoming spat is based on wall clock

Definition at line 709 of file WMListenerWorker.cpp.

710{
711 world_model_->sim_.use_real_time_spat_in_sim_ = use_real_time_spat_in_sim;
712}

References world_model_.

◆ isUsingSimTime()

void carma_wm::WMListenerWorker::isUsingSimTime ( bool  use_sim_time) const

set true if simulation_mode is on

Definition at line 705 of file WMListenerWorker.cpp.

706{
707 world_model_->sim_.use_sim_time_ = use_sim_time;
708}

References world_model_.

◆ mapCallback()

void carma_wm::WMListenerWorker::mapCallback ( const autoware_lanelet2_msgs::msg::MapBin::SharedPtr  map_msg)

Callback for new map messages. Updates the underlying map.

Parameters
map_msgThe new map messages to generate the map from

Definition at line 57 of file WMListenerWorker.cpp.

58{
59 current_map_version_ = map_msg->map_version;
60
61 lanelet::LaneletMapPtr new_map(new lanelet::LaneletMap);
62
64
65 world_model_->setMap(new_map, current_map_version_);
66
67 // After setting map evaluate the current update queue to apply any updates that arrived before the map
68 bool more_updates_to_apply = true;
69 while(!map_update_queue_.empty() && more_updates_to_apply) {
70
71 auto update = map_update_queue_.front(); // Get first update
72 map_update_queue_.pop(); // Remove update from queue
73
74 if (update->map_version < current_map_version_) { // Drop any so far unapplied updates for the previous map
75 RCLCPP_WARN_STREAM(logger_, "There were unapplied updates in carma_wm when a new map was received.");
76 continue;
77 }
78 if (update->map_version == current_map_version_) { // Current update goes with current map
79 mapUpdateCallback(update); // Apply the update
80 } else {
81 RCLCPP_INFO_STREAM(logger_, "Done applying updates for new map. However, more updates are waiting for a future map.");
82 more_updates_to_apply = false; // If there is more updates queued that are not for this map version assume they are for a future map version
83 }
84
85 }
86
87 // Call user defined map callback
88 if (map_callback_)
89 {
91 }
92
94 if (delayed_route_msg_.get().map_version == current_map_version_) { // If there is a delayed route message to apply then do so
95 routeCallback(std::make_unique<carma_planning_msgs::msg::Route>(delayed_route_msg_.get()));
96 } else if (delayed_route_msg_.get().map_version < current_map_version_) {
97 RCLCPP_WARN_STREAM(logger_, "Dropping delayed route message which was never applied as updated map was not recieved");
98 delayed_route_msg_ = boost::none;
99 } else {
100 RCLCPP_INFO_STREAM(logger_, "There is a delayed route message still waiting to be applied in carma_wm");
101 }
102 }
103}
boost::optional< carma_planning_msgs::msg::Route > delayed_route_msg_
std::function< void()> map_callback_
void mapUpdateCallback(autoware_lanelet2_msgs::msg::MapBin::SharedPtr geofence_msg)
Callback for new map update messages (geofence). Updates the underlying map.
void routeCallback(const carma_planning_msgs::msg::Route::SharedPtr route_msg)
Callback for route message.
std::queue< autoware_lanelet2_msgs::msg::MapBin::SharedPtr > map_update_queue_
void fromBinMsg(const autoware_lanelet2_msgs::msg::MapBin &msg, std::shared_ptr< carma_wm::TrafficControl > gf_ptr, lanelet::LaneletMapPtr lanelet_map=nullptr)

References current_map_version_, delayed_route_msg_, carma_wm::fromBinMsg(), logger_, map_callback_, map_update_queue_, mapUpdateCallback(), routeCallback(), and world_model_.

Here is the call graph for this function:

◆ mapUpdateCallback()

void carma_wm::WMListenerWorker::mapUpdateCallback ( autoware_lanelet2_msgs::msg::MapBin::SharedPtr  geofence_msg)

Callback for new map update messages (geofence). Updates the underlying map.

Parameters
geofence_msgThe new map update messages to generate the map edits from

Definition at line 148 of file WMListenerWorker.cpp.

149{
150 RCLCPP_INFO_STREAM(logger_, "Map Update Being Evaluated. SeqNum: " << geofence_msg->seq_id);
151 if (rerouting_flag_) // no update should be applied if rerouting
152 {
153 RCLCPP_INFO_STREAM(logger_, "Currently new route is being processed. Queueing this update. Received seq: " << geofence_msg->seq_id << " prev seq: " << most_recent_update_msg_seq_);
154 map_update_queue_.emplace(geofence_msg);
155 return;
156 }
157 if (geofence_msg->seq_id <= most_recent_update_msg_seq_) {
158 RCLCPP_DEBUG_STREAM(logger_, "Dropping map update which has already been processed. Received seq: " << geofence_msg->seq_id << " prev seq: " << most_recent_update_msg_seq_);
159 return;
160 } else if(!world_model_->getMap() || current_map_version_ < geofence_msg->map_version) { // If our current map version is older than the version target by this update
161 RCLCPP_DEBUG_STREAM(logger_, "Update received for newer map version than available. Queueing update until map is available.");
162 map_update_queue_.emplace(geofence_msg);
163 return;
164 } else if (current_map_version_ > geofence_msg->map_version) { // If this update is for an older map
165 RCLCPP_WARN_STREAM(logger_, "Dropping old map update as newer map is already available.");
166 return;
167 } else if (most_recent_update_msg_seq_ + 1 < geofence_msg->seq_id) {
168 RCLCPP_INFO_STREAM(logger_, "Queuing map update as we are waiting on an earlier update to be applied. most_recent_update_msg_seq_: " << most_recent_update_msg_seq_ << "geofence_msg->seq_id: " << geofence_msg->seq_id);
169 map_update_queue_.emplace(geofence_msg);
170 return;
171 }
172
173
174 if(geofence_msg->invalidates_route==true && world_model_->getRoute())
175 {
176 rerouting_flag_=true;
178
179 RCLCPP_DEBUG_STREAM(logger_, "Received notice that route has been invalidated in mapUpdateCallback");
180
181 if(route_node_flag_!=true)
182 {
183 RCLCPP_INFO_STREAM(logger_, "Route is not yet available. Therefore queueing the update");
184 map_update_queue_.emplace(geofence_msg);
185 return;
186 }
187 }
188
189 most_recent_update_msg_seq_ = geofence_msg->seq_id; // Update current sequence count
190
191 auto gf_ptr = std::shared_ptr<carma_wm::TrafficControl>(new carma_wm::TrafficControl);
192
193 // convert ros msg to geofence object
194 carma_wm::fromBinMsg(*geofence_msg, gf_ptr, world_model_->getMutableMap());
195
196 RCLCPP_INFO_STREAM(logger_, "Processing Map Update with Geofence Id:" << gf_ptr->id_);
197
198 RCLCPP_DEBUG_STREAM(logger_, "Geofence id" << gf_ptr->id_ << " requests addition of lanelets size: " << gf_ptr->lanelet_additions_.size());
199 for (auto llt : gf_ptr->lanelet_additions_)
200 {
201 // world model here should blindly accept the map update received
202 RCLCPP_DEBUG_STREAM(logger_, "Adding new lanelet with id: " << llt.id());
203 auto left = llt.leftBound3d(); //new lanelet coming in
204
205 // updating incoming points' memory addresses with local ones of same ids
206 // so that lanelet library can recognize they are same objects
207 for (size_t i = 0; i < left.size(); i ++)
208 {
209 if (world_model_->getMutableMap()->pointLayer.exists(left[i].id())) //rewrite the memory address of new pts with that of local
210 {
211 llt.leftBound3d()[i] = world_model_->getMutableMap()->pointLayer.get(left[i].id());
212 }
213 }
214 auto right = llt.rightBound3d(); //new lanelet coming in
215 for (size_t i = 0; i < right.size(); i ++)
216 {
217 if (world_model_->getMutableMap()->pointLayer.exists(right[i].id())) //rewrite the memory address of new pts with that of local
218 {
219 llt.rightBound3d()[i] = world_model_->getMutableMap()->pointLayer.get(right[i].id());
220 }
221 }
222
223 world_model_->getMutableMap()->add(llt);
224 }
225
226 RCLCPP_DEBUG_STREAM(logger_, "Geofence id" << gf_ptr->id_ << " sends record of traffic_lights_id size: " << gf_ptr->traffic_light_id_lookup_.size());
227 for (auto const &[traffic_light_id, lanelet_id] : gf_ptr->traffic_light_id_lookup_)
228 {
229 RCLCPP_DEBUG_STREAM(logger_, "Adding new pair for traffic light ids: " << traffic_light_id << ", and lanelet::Id: " << lanelet_id);
230 world_model_->setTrafficLightIds(traffic_light_id, lanelet_id);
231 }
232
233 RCLCPP_DEBUG_STREAM(logger_, "Geofence id" << gf_ptr->id_ << " sends record of intersections size: " << gf_ptr->sim_.intersection_id_to_regem_id_.size());
234 if (gf_ptr->sim_.intersection_id_to_regem_id_.size() > 0)
235 {
236 world_model_->sim_ = gf_ptr->sim_;
238 }
239
240 RCLCPP_DEBUG_STREAM(logger_, "Geofence id" << gf_ptr->id_ << " requests removal of size: " << gf_ptr->remove_list_.size());
241 for (auto const &[lanelet_id, lanelet_to_remove] : gf_ptr->remove_list_)
242 {
243 auto parent_llt = world_model_->getMutableMap()->laneletLayer.get(lanelet_id);
244 // we can only check by id, if the element is there
245 // this is only for speed optimization, as world model here should blindly accept the map update received
246 auto regems_copy_to_check = parent_llt.regulatoryElements(); // save local copy as the regem can be deleted during iteration
247 RCLCPP_DEBUG_STREAM(logger_, "Regems found in lanelet: " << regems_copy_to_check.size());
248 for (auto regem: regems_copy_to_check)
249 {
250 // we can't use the deserialized element as its data address conflicts the one in this node
251 if (lanelet_to_remove->id() == regem->id()) world_model_->getMutableMap()->remove(parent_llt, regem);
252 }
253 RCLCPP_DEBUG_STREAM(logger_, "Regems left in lanelet after removal: " << parent_llt.regulatoryElements().size());
254
255 }
256
257 RCLCPP_INFO_STREAM(logger_, "Geofence id" << gf_ptr->id_ << " requests update of size: " << gf_ptr->update_list_.size());
258
259 // we should extract general regem to specific type of regem the geofence specifies
260 for (auto const &[lanelet_id, lanelet_to_update]: gf_ptr->update_list_)
261 {
262
263 auto parent_llt = world_model_->getMutableMap()->laneletLayer.get(lanelet_id);
264
265 auto regemptr_it = world_model_->getMutableMap()->regulatoryElementLayer.find(lanelet_to_update->id());
266
267 // if this regem is already in the map.
268 // This section is expected to be called to add back regulations which were previously removed by expired geofences.
269 if (regemptr_it != world_model_->getMutableMap()->regulatoryElementLayer.end())
270 {
271
272 RCLCPP_DEBUG_STREAM(logger_, "Reapplying previously existing element for lanelet id:" << parent_llt.id() << ", and regem id: " << regemptr_it->get()->id());
273 // again we should use the element with correct data address to be consistent
274 world_model_->getMutableMap()->update(parent_llt, *regemptr_it);
275 }
276 else // Updates are treated as new regulations after the old value was removed. In both cases we enter this block.
277 {
278 RCLCPP_DEBUG_STREAM(logger_, "New regulatory element at lanelet: " << parent_llt.id() << ", and id: " << lanelet_to_update->id());
279 newRegemUpdateHelper(parent_llt, lanelet_to_update.get());
280 }
281 }
282
283 // set the Map to trigger a new route graph construction if rerouting was required by the updates and a new graph was not provided
284 world_model_->setMap(world_model_->getMutableMap(), current_map_version_, recompute_route_flag_ && !geofence_msg->has_routing_graph );
285
286 // If a new graph was provided then set that graph
287 // recompute_route_flag_ not checked here to support the case of the first map or map version changing
288 if (geofence_msg->has_routing_graph) {
289
290 LaneletRoutingGraphPtr graph = routingGraphFromMsg(geofence_msg->routing_graph, world_model_->getMutableMap());
291
292 if (!graph) {
293 throw std::invalid_argument("Map updated provided routing graph which could not be applied to the current map.");
294 }
295
296 world_model_->setRoutingGraph(graph);
297
298 }
299
300 // no need to reroute again unless received invalidated msg again
302 recompute_route_flag_ = false;
303
304
305 RCLCPP_INFO_STREAM(logger_, "Finished Applying the Map Update with Geofence Id:" << gf_ptr->id_);
306
307 // Call user defined map callback
308 if (map_callback_)
309 {
310 RCLCPP_INFO_STREAM(logger_, "Calling user defined map update callback");
312 }
313}
void newRegemUpdateHelper(lanelet::Lanelet parent_llt, lanelet::RegulatoryElement *regem) const
This is a helper function updates the parent_llt with specified regem. This function is needed as we ...
LaneletRoutingGraphPtr routingGraphFromMsg(const autoware_lanelet2_msgs::msg::RoutingGraph &msg, lanelet::LaneletMapPtr map) const
Helper function to convert a routing graph message into a actual RoutingGraph object.
std::shared_ptr< lanelet::routing::RoutingGraph > LaneletRoutingGraphPtr
Definition: WorldModel.hpp:52
void logSignalizedIntersectionManager(const carma_wm::SignalizedIntersectionManager &sim, const rclcpp::Logger &logger)

References current_map_version_, carma_wm::fromBinMsg(), process_bag::i, logger_, carma_wm::logSignalizedIntersectionManager(), map_callback_, map_update_queue_, most_recent_update_msg_seq_, newRegemUpdateHelper(), recompute_route_flag_, rerouting_flag_, route_node_flag_, routingGraphFromMsg(), and world_model_.

Referenced by mapCallback(), and routeCallback().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ newRegemUpdateHelper()

void carma_wm::WMListenerWorker::newRegemUpdateHelper ( lanelet::Lanelet  parent_llt,
lanelet::RegulatoryElement *  regem 
) const
private

This is a helper function updates the parent_llt with specified regem. This function is needed as we need to dynamic_cast from general regem to specific type of regem based on the geofence.

Parameters
parent_lltThe Lanelet that need to register the regem
regemlanelet::RegulatoryElement* which is the type that the serializer decodes from binary NOTE: Currently this function supports items in carma_wm::GeofenceType

Definition at line 323 of file WMListenerWorker.cpp.

324{
325 auto factory_regem = lanelet::RegulatoryElementFactory::create(regem->attribute(lanelet::AttributeName::Subtype).value(),
326 std::const_pointer_cast<lanelet::RegulatoryElementData>(regem->constData()));
327
328 // we should extract general regem to specific type of regem the geofence specifies
329 switch(resolveGeofenceType(regem->attribute(lanelet::AttributeName::Subtype).value()))
330 {
332 {
333 lanelet::PassingControlLinePtr control_line = std::dynamic_pointer_cast<lanelet::PassingControlLine>(factory_regem);
334 if (control_line)
335 {
336 world_model_->getMutableMap()->update(parent_llt, control_line);
337 }
338 else
339 {
340 std::invalid_argument("Dynamic Pointer cast failed on getting valid control line");
341 }
342
343 break;
344 }
346 {
347 lanelet::DigitalSpeedLimitPtr speed = std::dynamic_pointer_cast<lanelet::DigitalSpeedLimit>(factory_regem);
348 if (speed)
349 {
350 world_model_->getMutableMap()->update(parent_llt, speed);
351 }
352 else
353 {
354 std::invalid_argument("Dynamic Pointer cast failed on getting valid speed limit");
355 }
356 break;
357 }
359 {
360
361 lanelet::RegionAccessRulePtr rar = std::dynamic_pointer_cast<lanelet::RegionAccessRule>(factory_regem);
362 if (rar)
363 {
364 world_model_->getMutableMap()->update(parent_llt, rar);
365 }
366 else
367 {
368 std::invalid_argument("Dynamic Pointer cast failed on getting valid region access rule");
369 }
370
371 break;
372 }
374 {
375
376 lanelet::DigitalMinimumGapPtr min_gap = std::dynamic_pointer_cast<lanelet::DigitalMinimumGap>(factory_regem);
377 if (min_gap)
378 {
379 world_model_->getMutableMap()->update(parent_llt, min_gap);
380 }
381 else
382 {
383 std::invalid_argument("Dynamic Pointer cast failed on getting valid minimum gap rule");
384 }
385
386 break;
387 }
389 {
390
391 lanelet::DirectionOfTravelPtr dot = std::dynamic_pointer_cast<lanelet::DirectionOfTravel>(factory_regem);
392 if (dot)
393 {
394 world_model_->getMutableMap()->update(parent_llt, dot);
395 }
396 else
397 {
398 std::invalid_argument("Dynamic Pointer cast failed on getting valid direction of travel");
399 }
400
401 break;
402 }
404 {
405
406 lanelet::StopRulePtr sr = std::dynamic_pointer_cast<lanelet::StopRule>(factory_regem);
407 if (sr)
408 {
409 world_model_->getMutableMap()->update(parent_llt, sr);
410 }
411 else
412 {
413 std::invalid_argument("Dynamic Pointer cast failed on getting valid stop rule");
414 }
415 break;
416 }
418 {
419 lanelet::CarmaTrafficSignalPtr ctl = std::dynamic_pointer_cast<lanelet::CarmaTrafficSignal>(factory_regem);
420 if (ctl)
421 {
422 world_model_->getMutableMap()->update(parent_llt, ctl);
423 }
424 else
425 {
426 std::invalid_argument("Dynamic Pointer cast failed on getting valid carma traffic signal");
427 }
428 break;
429 }
431 {
432 lanelet::SignalizedIntersectionPtr si = std::dynamic_pointer_cast<lanelet::SignalizedIntersection>(factory_regem);
433 if (si)
434 {
435 world_model_->getMutableMap()->update(parent_llt, si);
436 }
437 else
438 {
439 std::invalid_argument("Dynamic Pointer cast failed on getting valid signalized intersection");
440 }
441
442 break;
443 }
444 default:
445 RCLCPP_WARN_STREAM(logger_, "World Model instance received an unsupported geofence type in its map update callback!");
446 break;
447 }
448}
GeofenceType resolveGeofenceType(const std::string &rule_name)

References carma_wm::CARMA_TRAFFIC_LIGHT, carma_wm::DIGITAL_MINIMUM_GAP, carma_wm::DIGITAL_SPEED_LIMIT, carma_wm::DIRECTION_OF_TRAVEL, logger_, carma_wm::PASSING_CONTROL_LINE, carma_wm::REGION_ACCESS_RULE, carma_wm::resolveGeofenceType(), carma_wm::SIGNALIZED_INTERSECTION, carma_wm::STOP_RULE, and world_model_.

Referenced by mapUpdateCallback().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ roadwayObjectListCallback()

void carma_wm::WMListenerWorker::roadwayObjectListCallback ( const carma_perception_msgs::msg::RoadwayObstacleList::SharedPtr  msg)

Callback for roadway objects msg.

Definition at line 574 of file WMListenerWorker.cpp.

575{
576 // this topic publishes only the objects that are on the road
577 world_model_->setRoadwayObjects(msg->roadway_obstacles);
578}

References world_model_.

◆ ros1ClockCallback()

void carma_wm::WMListenerWorker::ros1ClockCallback ( const rosgraph_msgs::msg::Clock::SharedPtr  clock_msg)

Callback for ROS1 clock message (used in Simulation runs)

Definition at line 580 of file WMListenerWorker.cpp.

581{
582 world_model_->setRos1Clock(rclcpp::Time(clock_msg->clock));
583}

References world_model_.

◆ routeCallback()

void carma_wm::WMListenerWorker::routeCallback ( const carma_planning_msgs::msg::Route::SharedPtr  route_msg)

Callback for route message.

Definition at line 590 of file WMListenerWorker.cpp.

591{
592 if (route_msg->map_version < current_map_version_) {
593 RCLCPP_WARN_STREAM(logger_, "Route message rejected as it is for an older map");
594 rerouting_flag_ = false; // Clear any blockers on map updates as the route we were waiting for is no longer valid
595 return;
596 }
597
598 if (route_msg->map_version > current_map_version_) {
599 RCLCPP_WARN_STREAM(logger_, "Route message received for future map. Delaying application until map is recieved");
600 delayed_route_msg_ = *route_msg;
601 return;
602 }
603
604 bool route_invalidated_by_queued_map_update = false; // Flag to indicate whether this new route has been invalidated due to one of the applied queued map updates
605 if(rerouting_flag_==true && route_msg->is_rerouted )
606
607 {
608
609 rerouting_flag_ = false; // Reset flag since the route node has finished re-routing
610
611 // After setting map evaluate the current update queue to apply any updates that arrived before the map
612 bool more_updates_to_apply = true;
613 while(!map_update_queue_.empty() && more_updates_to_apply) {
614
615 auto update = map_update_queue_.front(); // Get first update
616 map_update_queue_.pop(); // Remove update from queue
617
618 if (update->map_version < current_map_version_) { // Drop any so far unapplied updates for the current map
619 RCLCPP_WARN_STREAM(logger_, "Apply from reroute: There were unapplied updates in carma_wm when a new map was recieved.");
620 continue;
621 }
622 if (update->map_version == current_map_version_) { // Current update goes with current map which is also the map used by this route
623 RCLCPP_DEBUG_STREAM(logger_, "Applying queued update after route was recieved. ");
624
625 if (update->invalidates_route == true) {
626 RCLCPP_DEBUG_STREAM(logger_, "Applied queued map update has invalidated the route.");
627 route_invalidated_by_queued_map_update = true;
628 }
629
630 update->invalidates_route=false; // Do not trigger recomputation of routing graph in mapUpdateCallback; recomputation of routing graph will occur outside of this loop
631
632 mapUpdateCallback(update); // Apply the update
633 } else {
634 RCLCPP_INFO_STREAM(logger_, "Apply from reroute: Done applying updates for new map. However, more updates are waiting for a future map.");
635 more_updates_to_apply = false; // If there is more updates queued that are not for this map version assume they are for a future map version
636 }
637
638 }
639
640 }
641
642 if (!world_model_->getMap()) { // This check is a bit redundant but still useful from a debugging perspective as the alternative is a segfault
643 RCLCPP_ERROR_STREAM(logger_, "WMListener received a route before a map was available. Dropping route message.");
644 return;
645 }
646
647 // If one of the applied queued map updates invalidated the route, then the routing graph must be updated again for the route node
648 if (route_invalidated_by_queued_map_update && route_node_flag_){
649 RCLCPP_DEBUG_STREAM(logger_,"At least one applied queued map update has invalidated the route. Routing graph will be recomputed.");
650 world_model_->setMap(world_model_->getMutableMap(), current_map_version_, route_invalidated_by_queued_map_update);
651 RCLCPP_DEBUG_STREAM(logger_,"Finished recomputing the routing graph for the applied queued map update(s)");
652
653 rerouting_flag_ = true; // Set flag to trigger a route update by the route node due to the updated routing graph
654
655 return;
656 }
657 else {
658 rerouting_flag_ = false; // Reset flag since no applied queued map updates invalidated the route for the route node
659
660 auto path = lanelet::ConstLanelets();
661 for(auto id : route_msg->shortest_path_lanelet_ids)
662 {
663 auto ll = world_model_->getMap()->laneletLayer.get(id);
664 path.push_back(ll);
665 }
666
667 auto route_opt = path.size() == 1 ? world_model_->getMapRoutingGraph()->getRoute(path.front(), path.back())
668 : world_model_->getMapRoutingGraph()->getRouteVia(path.front(), lanelet::ConstLanelets(path.begin() + 1, path.end() - 1), path.back());
669 if(route_opt.is_initialized()) {
670 RCLCPP_DEBUG_STREAM(logger_, "Setting route in world model");
671 auto ptr = std::make_shared<lanelet::routing::Route>(std::move(route_opt.get()));
672 world_model_->setRoute(ptr);
673 }
674
675 world_model_->setRouteEndPoint({route_msg->end_point.x,route_msg->end_point.y,route_msg->end_point.z});
676 world_model_->setRouteName(route_msg->route_name);
677
678 // Call route_callback_
679 if (route_callback_)
680 {
682 }
683
684 return;
685 }
686}
std::function< void()> route_callback_

References current_map_version_, delayed_route_msg_, logger_, map_update_queue_, mapUpdateCallback(), rerouting_flag_, route_callback_, route_node_flag_, and world_model_.

Referenced by mapCallback().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ routingGraphFromMsg()

LaneletRoutingGraphPtr carma_wm::WMListenerWorker::routingGraphFromMsg ( const autoware_lanelet2_msgs::msg::RoutingGraph &  msg,
lanelet::LaneletMapPtr  map 
) const

Helper function to convert a routing graph message into a actual RoutingGraph object.

Parameters
msgThe graph message to convert
mapThe base map this graph applies to
Returns
nullptr if the graph could not be constructed or the provided graph does not match the map

Definition at line 450 of file WMListenerWorker.cpp.

450 {
451
452 if (msg.participant_type.compare(getVehicleParticipationType()) != 0) {
453
454 RCLCPP_ERROR_STREAM(logger_,"Received routing graph does not have matching vehicle type for world model. WM Type: "
456 << " graph type: " << msg.participant_type
457 );
458
459 return nullptr;
460 }
461
462 // Get the lists of passable lanelets and areas
463 // Both these lists must be populated in the same order as the message to support later logic
464 lanelet::ConstLanelets passable_lanelets;
465 lanelet::ConstAreas passable_areas;
466
467 passable_lanelets.reserve(msg.lanelet_vertices.size());
468 passable_areas.reserve(msg.area_vertices.size());
469
470 try {
471
472 // All the passable lanelets and areas should be included as a vertext so just iterate over each and store
473 for (auto vertex : msg.lanelet_vertices) {
474 passable_lanelets.emplace_back(map->laneletLayer.get(vertex.lanelet_or_area));
475 }
476
477 for (auto vertex : msg.area_vertices) {
478 passable_areas.emplace_back(map->areaLayer.get(vertex.lanelet_or_area));
479 }
480
481 } catch(const lanelet::NoSuchPrimitiveError& e) {
482
483 RCLCPP_ERROR_STREAM(logger_, "Received routing graph specifies lanelets which do not match the current map version. Actual exception: " << e.what());
484
485 return nullptr;
486 }
487
488
489 // Build the submap
490 // This operation does increase in time as the number of lanelets and areas increase
491 // however testing shows it to less than 1% of the total routing graph build time so this is a reasonable operation to keep
492 auto passable_map = lanelet::utils::createConstSubmap(passable_lanelets, passable_areas);
493
494 // This is the actual graph object which is used to initialize a RoutingGraph
495 auto graph = std::make_unique<lanelet::routing::internal::RoutingGraphGraph>(msg.num_unique_routing_cost_ids);
496
497 // Vertex must be added first then the edge can be added
498 for (auto ll : passable_lanelets) {
499 graph->addVertex(lanelet::routing::internal::VertexInfo{ll});
500 }
501
502 for (auto area : passable_areas) {
503 graph->addVertex(lanelet::routing::internal::VertexInfo{area});
504 }
505
506 // Now we can add edges
507 for (size_t i = 0; i < msg.lanelet_vertices.size(); ++i) {
508
509 auto vertex = msg.lanelet_vertices[i];
510 auto lanelet = passable_lanelets[i]; // passable_lanelets should be in the same order based on how its constructed
511
512 for (size_t j = 0; j < vertex.lanelet_or_area_ids.size(); ++j) {
513
514 lanelet::routing::RelationType relation;
515
516 // Get relation
517 switch (vertex.edge_relations[j])
518 {
519 case autoware_lanelet2_msgs::msg::RoutingGraphVertexAndEdges::RELATION_SUCCESSOR:
520 relation = lanelet::routing::RelationType::Successor; break;
521
522 case autoware_lanelet2_msgs::msg::RoutingGraphVertexAndEdges::RELATION_LEFT:
523 relation = lanelet::routing::RelationType::Left; break;
524
525 case autoware_lanelet2_msgs::msg::RoutingGraphVertexAndEdges::RELATION_RIGHT:
527
528 case autoware_lanelet2_msgs::msg::RoutingGraphVertexAndEdges::RELATION_ADJACENT_LEFT:
529 relation = lanelet::routing::RelationType::AdjacentLeft; break;
530
531 case autoware_lanelet2_msgs::msg::RoutingGraphVertexAndEdges::RELATION_ADJACENT_RIGHT:
532 relation = lanelet::routing::RelationType::AdjacentRight; break;
533
534 case autoware_lanelet2_msgs::msg::RoutingGraphVertexAndEdges::RELATION_CONFLICTING:
535 relation = lanelet::routing::RelationType::Conflicting; break;
536
537 case autoware_lanelet2_msgs::msg::RoutingGraphVertexAndEdges::RELATION_AREA:
538 relation = lanelet::routing::RelationType::Area; break;
539
540 default: // Treat default as RELATION_NONE
541 relation = lanelet::routing::RelationType::None; break;
542 }
543
544 try {
545
546 // Create edge
547 graph->addEdge(
548 lanelet,
549 map->laneletLayer.get(vertex.lanelet_or_area_ids[j]),
550 lanelet::routing::internal::EdgeInfo{vertex.edge_routing_costs[j], vertex.edge_routing_cost_source_ids[j], relation}
551 );
552
553 } catch(const lanelet::NoSuchPrimitiveError& e) {
554
555 RCLCPP_ERROR_STREAM(logger_,"Received routing graph specifies lanelets which do not match the current map version. Not found lanelet or area: "
556 << vertex.lanelet_or_area_ids[j] << " Actual exception: " << e.what());
557
558 return nullptr;
559 }
560
561 }
562 }
563
564 // Build and return the final initialized routing graph
565 return std::make_shared<lanelet::routing::RoutingGraph>(std::move(graph), std::move(passable_map));
566
567}
std::string getVehicleParticipationType() const
Returns the Vehicle Participation Type value.

References getVehicleParticipationType(), process_bag::i, sci_strategic_plugin::Left, logger_, and sci_strategic_plugin::Right.

Referenced by mapUpdateCallback().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ setConfigSpeedLimit()

void carma_wm::WMListenerWorker::setConfigSpeedLimit ( double  config_lim)

Allows user to set a callback to be triggered when a map update is received.

Parameters
config_limA callback function that will be triggered after the world model receives a new map update

Definition at line 698 of file WMListenerWorker.cpp.

699{
700 config_speed_limit_ = config_lim;
701 //Function to load config_limit into CarmaWorldModel
702 world_model_->setConfigSpeedLimit(config_speed_limit_);
703}

References config_speed_limit_, and world_model_.

◆ setMapCallback()

void carma_wm::WMListenerWorker::setMapCallback ( std::function< void()>  callback)

Allows user to set a callback to be triggered when a map update is received.

Parameters
callbackA callback function that will be triggered after the world model receives a new map update

Definition at line 688 of file WMListenerWorker.cpp.

689{
690 map_callback_ = callback;
691}

References map_callback_.

◆ setRouteCallback()

void carma_wm::WMListenerWorker::setRouteCallback ( std::function< void()>  callback)

Allows user to set a callback to be triggered when a route update is received.

Parameters
callbackA callback function that will be triggered after the world model is updated with a new route

Definition at line 693 of file WMListenerWorker.cpp.

694{
695 route_callback_ = callback;
696}

References route_callback_.

◆ setVehicleParticipationType()

void carma_wm::WMListenerWorker::setVehicleParticipationType ( std::string  participant)

Allows user to set a callback to be triggered when a map update is received.

Parameters
participantA callback function that will be triggered after the world model receives a new map update

Definition at line 730 of file WMListenerWorker.cpp.

731{
732 //Function to load participation type into CarmaWorldModel
733 world_model_->setVehicleParticipationType(participant);
734}

References world_model_.

◆ setWMSpatProcessingState()

void carma_wm::WMListenerWorker::setWMSpatProcessingState ( const SIGNAL_PHASE_PROCESSING phase_type) const

Activate World Model SPAT processor, which is turned off by default, with OFF (0), ON (1), FIXED (2)

Definition at line 714 of file WMListenerWorker.cpp.

716{
717 world_model_->sim_.spat_processor_state_ = phase_type;
718}

References world_model_.

◆ simClockCallback()

void carma_wm::WMListenerWorker::simClockCallback ( const rosgraph_msgs::msg::Clock::SharedPtr  clock_msg)

Callback for Simulation clock message (used in Simulation runs)

Definition at line 585 of file WMListenerWorker.cpp.

586{
587 world_model_->setSimulationClock(rclcpp::Time(clock_msg->clock));
588}

References world_model_.

Member Data Documentation

◆ config_speed_limit_

double carma_wm::WMListenerWorker::config_speed_limit_
private

Definition at line 182 of file WMListenerWorker.hpp.

Referenced by getConfigSpeedLimit(), and setConfigSpeedLimit().

◆ current_map_version_

size_t carma_wm::WMListenerWorker::current_map_version_ = 0
private

Definition at line 184 of file WMListenerWorker.hpp.

Referenced by mapCallback(), mapUpdateCallback(), and routeCallback().

◆ delayed_route_msg_

boost::optional<carma_planning_msgs::msg::Route> carma_wm::WMListenerWorker::delayed_route_msg_
private

Definition at line 186 of file WMListenerWorker.hpp.

Referenced by mapCallback(), and routeCallback().

◆ logger_

rclcpp::Logger carma_wm::WMListenerWorker::logger_
private

◆ map_callback_

std::function<void()> carma_wm::WMListenerWorker::map_callback_
private

Definition at line 179 of file WMListenerWorker.hpp.

Referenced by mapCallback(), mapUpdateCallback(), and setMapCallback().

◆ map_update_queue_

std::queue<autoware_lanelet2_msgs::msg::MapBin::SharedPtr> carma_wm::WMListenerWorker::map_update_queue_
private

Definition at line 185 of file WMListenerWorker.hpp.

Referenced by mapCallback(), mapUpdateCallback(), and routeCallback().

◆ most_recent_update_msg_seq_

long carma_wm::WMListenerWorker::most_recent_update_msg_seq_ = -1
private

Definition at line 191 of file WMListenerWorker.hpp.

Referenced by mapUpdateCallback().

◆ recompute_route_flag_

bool carma_wm::WMListenerWorker::recompute_route_flag_ =false
private

Definition at line 188 of file WMListenerWorker.hpp.

Referenced by mapUpdateCallback().

◆ rerouting_flag_

bool carma_wm::WMListenerWorker::rerouting_flag_ =false
private

Definition at line 189 of file WMListenerWorker.hpp.

Referenced by checkIfReRoutingNeeded(), mapUpdateCallback(), and routeCallback().

◆ route_callback_

std::function<void()> carma_wm::WMListenerWorker::route_callback_
private

Definition at line 180 of file WMListenerWorker.hpp.

Referenced by routeCallback(), and setRouteCallback().

◆ route_node_flag_

bool carma_wm::WMListenerWorker::route_node_flag_ =false
private

◆ world_model_


The documentation for this class was generated from the following files: