scenario_simulator_v2 C++ API
traffic_lights.hpp
Go to the documentation of this file.
1 // Copyright 2015 TIER IV, Inc. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef TRAFFIC_SIMULATOR__TRAFFIC_LIGHTS__TRAFFIC_LIGHTS_HPP_
16 #define TRAFFIC_SIMULATOR__TRAFFIC_LIGHTS__TRAFFIC_LIGHTS_HPP_
17 
18 // This message will be deleted in the future
19 #if __has_include(<autoware_perception_msgs/msg/traffic_signal_array.hpp>)
20 #include <autoware_perception_msgs/msg/traffic_signal_array.hpp>
21 #endif
22 
23 #if __has_include(<autoware_perception_msgs/msg/traffic_light_group_array.hpp>)
24 #include <autoware_perception_msgs/msg/traffic_light_group_array.hpp>
25 #endif
26 
27 #include <algorithm>
28 #include <set>
32 
33 namespace traffic_simulator
34 {
36 {
37 public:
38  template <typename NodeTypePointer>
39  explicit ConventionalTrafficLights(const NodeTypePointer & node_ptr)
40  : TrafficLightsBase(node_ptr),
41  backward_compatible_publisher_ptr_(
42  std::make_unique<TrafficLightPublisher<traffic_simulator_msgs::msg::TrafficLightArrayV1>>(
43  node_ptr, "/simulation/traffic_lights"))
44  {
45  }
46 
47  ~ConventionalTrafficLights() override = default;
48 
49 private:
50  auto update() const -> void override
51  {
52  backward_compatible_publisher_ptr_->publish(
55  marker_publisher_ptr_->deleteMarkers();
56  }
58  }
59 
60  const std::unique_ptr<TrafficLightPublisherBase> backward_compatible_publisher_ptr_;
61 };
62 
64 {
65 public:
66  auto setState(const lanelet::Id lanelet_id, const std::string & state) -> void
67  {
68  clearState(lanelet_id);
69  addState(lanelet_id, state);
70  }
71 
72  auto addState(const lanelet::Id lanelet_id, const std::string & state) -> void
73  {
74  auto [iter, inserted] = detected_traffic_lights_.try_emplace(lanelet_id, lanelet_id);
75  iter->second.set(state);
76  }
77 
78  auto clearState(const lanelet::Id lanelet_id) -> bool
79  {
80  return detected_traffic_lights_.erase(lanelet_id) > 0;
81  }
82 
83  auto empty() const -> bool { return detected_traffic_lights_.empty(); }
84 
85  auto apply(simulation_api_schema::UpdateTrafficLightsRequest & request) const -> void
86  {
87  for (const auto & [lanelet_id, detected_light] : detected_traffic_lights_) {
88  if (auto matched_state = std::find_if(
89  request.mutable_states()->begin(), request.mutable_states()->end(),
90  [lanelet_id](const auto & state) { return state.id() == lanelet_id; });
91  matched_state != request.mutable_states()->end()) {
92  // Only update traffic_light_status (bulbs), preserve relation_ids
93  auto detected_signal = static_cast<simulation_api_schema::TrafficSignal>(detected_light);
94  matched_state->clear_traffic_light_status();
95  for (const auto & status : detected_signal.traffic_light_status()) {
96  *matched_state->add_traffic_light_status() = status;
97  }
98  } else {
99  // add ground-truth-less detected traffic light
100  *request.add_states() = static_cast<simulation_api_schema::TrafficSignal>(detected_light);
101  }
102  }
103  }
104 
105 private:
106  std::map<lanelet::Id, TrafficLight> detected_traffic_lights_;
107 };
108 
110 {
111 public:
112  template <typename NodeTypePointer>
113  explicit V2ITrafficLights(const NodeTypePointer & node_ptr, const std::string & architecture_type)
114  : TrafficLightsBase(node_ptr),
115  publisher_ptr_(makePublisher(
116  node_ptr, architecture_type,
117  "/perception/traffic_light_recognition/external/traffic_signals")),
118  legacy_topic_publisher_ptr_(makePublisher(node_ptr, architecture_type, "/v2x/traffic_signals"))
119  {
120  }
121 
122  ~V2ITrafficLights() override = default;
123 
124  auto setDetectedTrafficLights(std::shared_ptr<DetectedTrafficLights> detected) -> void
125  {
126  detected_ = detected;
127  }
128 
130  const lanelet::Id lanelet_id, const std::string & state, double time_ahead_seconds) -> void;
131 
132  auto clearTrafficLightsStatePredictions() -> void;
133 
134 private:
135  auto update() const -> void override
136  {
137  const auto now = clock_ptr_->now();
138  auto request = generateUpdateTrafficLightsRequest();
139  if (detected_) {
140  detected_->apply(request);
141  }
142  publisher_ptr_->publish(now, request, &predictions_);
143  legacy_topic_publisher_ptr_->publish(now, request, &predictions_);
144  if (isAnyTrafficLightChanged()) {
145  marker_publisher_ptr_->deleteMarkers();
146  }
148  }
149 
150  template <typename NodeTypePointer>
151  auto makePublisher(
152  const NodeTypePointer & node_ptr, const std::string & architecture_type,
153  const std::string & topic_name) -> std::unique_ptr<TrafficLightPublisherBase>
154  {
155  /*
156  V2ITrafficLights in TrafficSimulator publishes using architecture-independent topics ("awf/universe..."):
157  "/v2x/traffic_signals" and "/perception/traffic_light_recognition/external/traffic_signals"
158 
159  TrafficLightsDetector in SimpleSensorSimulator publishes using architecture-dependent topics:
160  "/perception/traffic_light_recognition/internal/traffic_signals" for >= "awf/universe/20230906"
161  "/perception/traffic_light_recognition/traffic_signals" for "awf/universe"
162  */
163  if (architecture_type == "awf/universe") {
164  throw common::SemanticError(
165  "This version of scenario_simulator_v2 does not support ", std::quoted(architecture_type),
166  " as ", std::quoted("architecture_type"), ". Please use older version.");
167 #if __has_include(<autoware_perception_msgs/msg/traffic_signal_array.hpp>)
168  } else if (architecture_type <= "awf/universe/20230906") {
169  return std::make_unique<
170  TrafficLightPublisher<autoware_perception_msgs::msg::TrafficSignalArray>>(
171  node_ptr, topic_name);
172 #endif
173 #if __has_include(<autoware_perception_msgs/msg/traffic_light_group_array.hpp>)
174  } else if (architecture_type >= "awf/universe/20240605") {
175  return std::make_unique<
176  TrafficLightPublisher<autoware_perception_msgs::msg::TrafficLightGroupArray>>(
177  node_ptr, topic_name);
178 #endif
179  } else {
180  throw common::SemanticError(
181  "Unexpected architecture_type ", std::quoted(architecture_type),
182  " given for V2I traffic lights simulation.");
183  }
184  }
185 
186  const std::unique_ptr<TrafficLightPublisherBase> publisher_ptr_;
187 
188  const std::unique_ptr<TrafficLightPublisherBase> legacy_topic_publisher_ptr_;
189 
190  std::shared_ptr<DetectedTrafficLights> detected_;
191 
192  TrafficLightStatePredictions predictions_;
193 };
194 
195 template <typename GroundTruthType>
197 {
198 public:
199  template <typename NodeTypePointer, typename... Args>
200  explicit TrafficLightsChannel(const NodeTypePointer & node_ptr, Args &&... args)
201  : ground_truth_(std::make_shared<GroundTruthType>(node_ptr, std::forward<Args>(args)...)),
202  detected_(std::make_shared<DetectedTrafficLights>())
203  {
204  }
205 
206  auto getGroundTruth() const -> std::shared_ptr<GroundTruthType> { return ground_truth_; }
207 
208  auto getDetected() const -> std::shared_ptr<DetectedTrafficLights> { return detected_; }
209 
210  auto hasDetectedChanges() const -> bool { return not detected_->empty(); }
211 
212  auto generateUpdateRequest() const -> simulation_api_schema::UpdateTrafficLightsRequest
213  {
214  auto request = ground_truth_->generateUpdateTrafficLightsRequest();
215  detected_->apply(request);
216  return request;
217  }
218 
219 private:
220  std::shared_ptr<GroundTruthType> ground_truth_;
221 
222  std::shared_ptr<DetectedTrafficLights> detected_;
223 };
224 
226 {
227 public:
228  template <typename NodeTypePointer>
229  explicit TrafficLights(const NodeTypePointer & node_ptr, const std::string & architecture_type)
230  : conventional_channel_(node_ptr), v2i_channel_(node_ptr, architecture_type)
231  {
232  v2i_channel_.getGroundTruth()->setDetectedTrafficLights(v2i_channel_.getDetected());
233 
234  conventional_channel_.getGroundTruth()->registerStateChangeCallback(
235  [this, v2i = v2i_channel_.getGroundTruth()](
236  lanelet::Id lanelet_id, const std::string & state,
238  if (v2i_enabled_traffic_lights_.count(lanelet_id) > 0) {
239  switch (change_type) {
240  case TrafficLightsBase::StateChangeType::SET:
241  v2i->setTrafficLightsState(lanelet_id, state);
242  break;
243  case TrafficLightsBase::StateChangeType::CLEAR:
244  v2i->clearTrafficLightsState(lanelet_id);
245  break;
246  case TrafficLightsBase::StateChangeType::ADD:
247  v2i->addTrafficLightsState(lanelet_id, state);
248  break;
249  }
250  }
251  });
252  }
253 
254  auto setV2IFeature(const lanelet::Id lanelet_id, const bool enabled) -> void
255  {
257  for (const auto & traffic_light_way_id :
259  setV2IFeature(traffic_light_way_id, enabled);
260  }
261  } else if (lanelet_wrapper::traffic_lights::isTrafficLight(lanelet_id)) {
262  // way ID -> use directly
263  if (enabled) {
264  v2i_enabled_traffic_lights_.insert(lanelet_id);
265  } else {
266  v2i_enabled_traffic_lights_.erase(lanelet_id);
267  }
268  }
269  }
270 
271  auto isAnyTrafficLightChanged() -> bool;
272 
273  auto startTrafficLightsUpdate(
274  const double conventional_traffic_light_update_rate,
275  const double v2i_traffic_lights_update_rate) -> void;
276 
277  auto getConventionalTrafficLights() const -> std::shared_ptr<ConventionalTrafficLights>;
278 
279  auto getV2ITrafficLights() const -> std::shared_ptr<V2ITrafficLights>;
280 
281  auto getConventionalDetectedTrafficLights() const -> std::shared_ptr<DetectedTrafficLights>;
282 
283  auto getV2IDetectedTrafficLights() const -> std::shared_ptr<DetectedTrafficLights>;
284 
285  auto generateConventionalUpdateRequest() const
286  -> simulation_api_schema::UpdateTrafficLightsRequest;
287 
288  auto isV2ITrafficLightEnabled(const lanelet::Id lanelet_id) const -> bool;
289 
290 private:
291  TrafficLightsChannel<ConventionalTrafficLights> conventional_channel_;
292 
294 
295  std::set<lanelet::Id> v2i_enabled_traffic_lights_;
296 };
297 } // namespace traffic_simulator
298 #endif // TRAFFIC_SIMULATOR__TRAFFIC_LIGHTS__TRAFFIC_LIGHTS_HPP_
Definition: traffic_lights.hpp:36
ConventionalTrafficLights(const NodeTypePointer &node_ptr)
Definition: traffic_lights.hpp:39
Definition: traffic_lights.hpp:64
auto setState(const lanelet::Id lanelet_id, const std::string &state) -> void
Definition: traffic_lights.hpp:66
auto clearState(const lanelet::Id lanelet_id) -> bool
Definition: traffic_lights.hpp:78
auto addState(const lanelet::Id lanelet_id, const std::string &state) -> void
Definition: traffic_lights.hpp:72
auto empty() const -> bool
Definition: traffic_lights.hpp:83
auto apply(simulation_api_schema::UpdateTrafficLightsRequest &request) const -> void
Definition: traffic_lights.hpp:85
Definition: traffic_light_publisher.hpp:39
Definition: traffic_lights_base.hpp:44
StateChangeType
Definition: traffic_lights_base.hpp:47
auto isAnyTrafficLightChanged() const -> bool
Definition: traffic_lights_base.cpp:32
auto generateUpdateTrafficLightsRequest() const -> simulation_api_schema::UpdateTrafficLightsRequest
Definition: traffic_lights_base.cpp:114
const rclcpp::Clock::SharedPtr clock_ptr_
Definition: traffic_lights_base.hpp:115
const std::unique_ptr< TrafficLightMarkerPublisher > marker_publisher_ptr_
Definition: traffic_lights_base.hpp:118
std::unordered_map< lanelet::Id, TrafficLight > traffic_lights_map_
Definition: traffic_lights_base.hpp:117
Definition: traffic_lights.hpp:197
auto getGroundTruth() const -> std::shared_ptr< GroundTruthType >
Definition: traffic_lights.hpp:206
TrafficLightsChannel(const NodeTypePointer &node_ptr, Args &&... args)
Definition: traffic_lights.hpp:200
auto getDetected() const -> std::shared_ptr< DetectedTrafficLights >
Definition: traffic_lights.hpp:208
auto generateUpdateRequest() const -> simulation_api_schema::UpdateTrafficLightsRequest
Definition: traffic_lights.hpp:212
auto hasDetectedChanges() const -> bool
Definition: traffic_lights.hpp:210
Definition: traffic_lights.hpp:226
TrafficLights(const NodeTypePointer &node_ptr, const std::string &architecture_type)
Definition: traffic_lights.hpp:229
auto setV2IFeature(const lanelet::Id lanelet_id, const bool enabled) -> void
Definition: traffic_lights.hpp:254
Definition: traffic_lights.hpp:110
V2ITrafficLights(const NodeTypePointer &node_ptr, const std::string &architecture_type)
Definition: traffic_lights.hpp:113
auto addTrafficLightsStatePrediction(const lanelet::Id lanelet_id, const std::string &state, double time_ahead_seconds) -> void
Definition: traffic_lights.cpp:67
auto clearTrafficLightsStatePredictions() -> void
Definition: traffic_lights.cpp:106
~V2ITrafficLights() override=default
auto setDetectedTrafficLights(std::shared_ptr< DetectedTrafficLights > detected) -> void
Definition: traffic_lights.hpp:124
Definition: lanelet_wrapper.hpp:43
auto isTrafficLightRegulatoryElement(const lanelet::Id lanelet_id) -> bool
Definition: traffic_lights.cpp:34
auto isTrafficLight(const lanelet::Id lanelet_id) -> bool
Definition: traffic_lights.cpp:23
auto wayIds(const lanelet::Id lanelet_id) -> lanelet::Ids
Definition: traffic_lights.cpp:21
Definition: operators.hpp:25
Definition: api.hpp:33
std::unordered_map< lanelet::Id, std::vector< std::pair< rclcpp::Time, std::vector< simulation_api_schema::TrafficLight > >> > TrafficLightStatePredictions
Definition: traffic_lights_base.hpp:35
std::string string
Definition: junit5.hpp:26
Although there were no syntactic errors in the description of the scenario, differences in meaning an...
Definition: exception.hpp:44