Skip to content

Commit 61d5bc6

Browse files
committed
wip
Signed-off-by: Tomohito Ando <tomohito.ando@tier4.jp>
1 parent b3d166a commit 61d5bc6

File tree

5 files changed

+372
-225
lines changed

5 files changed

+372
-225
lines changed

perception/traffic_light_arbiter/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ autoware_package()
66

77
ament_auto_add_library(${PROJECT_NAME} SHARED
88
src/traffic_light_arbiter.cpp
9+
src/signal_match_validator.cpp
910
)
1011

1112
rclcpp_components_register_nodes(${PROJECT_NAME}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright 2024 The Autoware Contributors
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_LIGHT_ARBITER__SIGNAL_MATCH_VALIDATOR_HPP_
16+
#define TRAFFIC_LIGHT_ARBITER__SIGNAL_MATCH_VALIDATOR_HPP_
17+
18+
#include <lanelet2_extension/utility/query.hpp>
19+
#include <rclcpp/rclcpp.hpp>
20+
21+
#include <autoware_perception_msgs/msg/traffic_signal_array.hpp>
22+
23+
#include <lanelet2_core/LaneletMap.h>
24+
25+
#include <memory>
26+
#include <optional>
27+
#include <unordered_set>
28+
#include <vector>
29+
30+
/**
31+
* @class SignalMatchValidator
32+
* @brief Validates and compares traffic signal data from different sources.
33+
*
34+
* This class is designed to compare and validate traffic signal information
35+
* received from internal (e.g. camera perception) and external (e.g. V2I communication).
36+
* It aims to ensure that the traffic signal information from both sources is consistent.
37+
*/
38+
class SignalMatchValidator
39+
{
40+
public:
41+
using TrafficSignalArray = autoware_perception_msgs::msg::TrafficSignalArray;
42+
using TrafficSignal = autoware_perception_msgs::msg::TrafficSignal;
43+
using TrafficSignalElement = autoware_perception_msgs::msg::TrafficSignalElement;
44+
using TrafficLightConstPtr = lanelet::TrafficLightConstPtr;
45+
46+
/**
47+
* @brief Default constructor for SignalMatchValidator.
48+
*/
49+
SignalMatchValidator() = default;
50+
51+
/**
52+
* @brief Validates and compares traffic signal data from perception and external sources.
53+
*
54+
* This method compares traffic signal data obtained from perception results
55+
* with data received from external source. It aims to find and return signals
56+
* that are present and consistent in both datasets. If signals are not consistent,
57+
* treat them as the unknown signal.
58+
*
59+
* @param perception_signals Traffic signal data from perception.
60+
* @param external_signals Traffic signal data from external source.
61+
* @return A validated TrafficSignalArray.
62+
*/
63+
TrafficSignalArray validateSignals(
64+
const TrafficSignalArray & perception_signals, const TrafficSignalArray & external_signals);
65+
66+
void setPedestrianSignals(const std::vector<TrafficLightConstPtr> & pedestrian_signals);
67+
68+
void setExternalPriority(const bool external_priority);
69+
70+
bool isPedestrianSignal(const lanelet::Id & signal_id);
71+
72+
private:
73+
bool external_priority_;
74+
std::unordered_set<lanelet::Id> map_pedestrian_signal_regulatory_elements_set_;
75+
};
76+
77+
#endif

perception/traffic_light_arbiter/include/traffic_light_arbiter/traffic_light_arbiter.hpp

+3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#define TRAFFIC_LIGHT_ARBITER__TRAFFIC_LIGHT_ARBITER_HPP_
1717

1818
#include <rclcpp/rclcpp.hpp>
19+
#include <traffic_light_arbiter/signal_match_validator.hpp>
1920

2021
#include <autoware_auto_mapping_msgs/msg/had_map_bin.hpp>
2122
#include <autoware_perception_msgs/msg/traffic_signal_array.hpp>
@@ -55,6 +56,8 @@ class TrafficLightArbiter : public rclcpp::Node
5556

5657
TrafficSignalArray latest_perception_msg_;
5758
TrafficSignalArray latest_external_msg_;
59+
60+
SignalMatchValidator signal_match_validator_;
5861
};
5962

6063
#endif // TRAFFIC_LIGHT_ARBITER__TRAFFIC_LIGHT_ARBITER_HPP_
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
// Copyright 2024 The Autoware Contributors
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+
#include "traffic_light_arbiter/signal_match_validator.hpp"
16+
17+
namespace util
18+
{
19+
using TrafficSignalArray = autoware_perception_msgs::msg::TrafficSignalArray;
20+
using TrafficSignal = autoware_perception_msgs::msg::TrafficSignal;
21+
using Element = autoware_perception_msgs::msg::TrafficSignalElement;
22+
23+
std::optional<TrafficSignal> find_signal_by_id(
24+
const TrafficSignalArray & signals, int64_t signal_id)
25+
{
26+
auto it = std::find_if(
27+
signals.signals.begin(), signals.signals.end(),
28+
[signal_id](const TrafficSignal & signal) { return signal.traffic_signal_id == signal_id; });
29+
if (it != signals.signals.end()) {
30+
return *it;
31+
} else {
32+
return std::nullopt;
33+
}
34+
}
35+
36+
Element create_element(
37+
const Element::_color_type & color, const Element::_shape_type & shape,
38+
const Element::_status_type & status, const Element::_confidence_type & confidence)
39+
{
40+
Element signal_element;
41+
signal_element.color = color;
42+
signal_element.shape = shape;
43+
signal_element.status = status;
44+
signal_element.confidence = confidence;
45+
46+
return signal_element;
47+
}
48+
49+
// Create unknown elements for each shape
50+
std::vector<Element> create_unknown_elements(
51+
const std::vector<Element> & elements1, const std::vector<Element> & elements2)
52+
{
53+
std::unordered_set<Element::_shape_type> shape_set;
54+
for (const auto & element : elements1) {
55+
shape_set.emplace(element.shape);
56+
}
57+
for (const auto & element : elements2) {
58+
shape_set.emplace(element.shape);
59+
}
60+
61+
std::vector<Element> unknown_elements;
62+
for (const auto & shape : shape_set) {
63+
// Confidence doesn't matter because this is the unknown signal
64+
unknown_elements.emplace_back(
65+
util::create_element(Element::UNKNOWN, shape, Element::UNKNOWN, /* confidence */ 1.0));
66+
}
67+
68+
return unknown_elements;
69+
}
70+
71+
TrafficSignal create_unknown_signal(const TrafficSignal & signal)
72+
{
73+
TrafficSignal unknown_signal;
74+
unknown_signal.traffic_signal_id = signal.traffic_signal_id;
75+
for (const auto & element : signal.elements) {
76+
// Confidence doesn't matter because this is the unknown signal
77+
const auto unknown_element =
78+
util::create_element(Element::UNKNOWN, element.shape, Element::UNKNOWN, /* confidence */ 1.0);
79+
unknown_signal.elements.emplace_back(unknown_element);
80+
}
81+
82+
return unknown_signal;
83+
}
84+
85+
TrafficSignal create_unknown_signal(const TrafficSignal & signal1, const TrafficSignal & signal2)
86+
{
87+
TrafficSignal unknown_signal;
88+
89+
// Assume that the both ids are same
90+
unknown_signal.traffic_signal_id = signal1.traffic_signal_id;
91+
92+
const auto unknown_elements = util::create_unknown_elements(signal1.elements, signal2.elements);
93+
for (const auto & element : unknown_elements) {
94+
unknown_signal.elements.emplace_back(element);
95+
}
96+
97+
return unknown_signal;
98+
}
99+
100+
bool are_all_elements_equivalent(
101+
const std::vector<Element> & signal1, const std::vector<Element> & signal2)
102+
{
103+
// Check if the vectors have the same size
104+
if (signal1.size() != signal2.size()) {
105+
return false;
106+
}
107+
108+
// Create copies of the vectors
109+
std::vector<Element> sorted_signal1 = signal1;
110+
std::vector<Element> sorted_signal2 = signal2;
111+
112+
// Sort based on the shape to ensure that they are same order
113+
auto compare_by_shape = [](const Element & a, const Element & b) { return a.shape < b.shape; };
114+
std::sort(sorted_signal1.begin(), sorted_signal1.end(), compare_by_shape);
115+
std::sort(sorted_signal2.begin(), sorted_signal2.end(), compare_by_shape);
116+
117+
// Compare the sorted vectors and return true if they have all the same elements
118+
return std::equal(
119+
sorted_signal1.begin(), sorted_signal1.end(), sorted_signal2.begin(), sorted_signal2.end(),
120+
[](const Element & a, const Element & b) { return a.color == b.color && a.shape == b.shape; });
121+
}
122+
123+
std::unordered_set<lanelet::Id> create_signal_id_set(
124+
const std::vector<TrafficSignal> & signals1, const std::vector<TrafficSignal> & signals2)
125+
{
126+
std::unordered_set<lanelet::Id> signal_id_set;
127+
for (const auto & signal : signals1) {
128+
signal_id_set.emplace(signal.traffic_signal_id);
129+
}
130+
for (const auto & signal : signals2) {
131+
signal_id_set.emplace(signal.traffic_signal_id);
132+
}
133+
134+
return signal_id_set;
135+
}
136+
137+
TrafficSignal get_highest_confidence_signal(
138+
const std::optional<TrafficSignal> & perception_signal,
139+
const std::optional<TrafficSignal> & external_signal, const bool external_priority)
140+
{
141+
// If the either of the signal doesn't exist, return the signal that exists
142+
if (!perception_signal) {
143+
return *external_signal;
144+
}
145+
if (!external_signal) {
146+
return *perception_signal;
147+
}
148+
149+
// If the external_priority is true, use the external results
150+
if (external_priority) {
151+
return *external_signal;
152+
}
153+
154+
// Create map using shape as key
155+
using Key = Element::_shape_type;
156+
std::map<Key, std::vector<Element>> shape_element_map;
157+
for (const auto & element : perception_signal->elements) {
158+
shape_element_map[element.shape].emplace_back(element);
159+
}
160+
for (const auto & element : external_signal->elements) {
161+
shape_element_map[element.shape].emplace_back(element);
162+
}
163+
164+
TrafficSignal highest_confidence_signal;
165+
166+
// Assume that the both ids are same
167+
highest_confidence_signal.traffic_signal_id = perception_signal->traffic_signal_id;
168+
169+
// Find the highest confidence element and push it
170+
for (const auto & shape_and_elements : shape_element_map) {
171+
const auto & elements = shape_and_elements.second;
172+
const auto highest_confidence_element = std::max_element(
173+
elements.begin(), elements.end(),
174+
[](const Element & a, const Element & b) { return a.confidence < b.confidence; });
175+
highest_confidence_signal.elements.emplace_back(*highest_confidence_element);
176+
}
177+
178+
return highest_confidence_signal;
179+
}
180+
181+
using Time = builtin_interfaces::msg::Time;
182+
Time get_newer_stamp(const Time & stamp1, const Time & stamp2)
183+
{
184+
if (stamp1.sec > stamp2.sec || (stamp1.sec == stamp2.sec && stamp1.nanosec > stamp2.nanosec)) {
185+
return stamp1;
186+
} else {
187+
return stamp2;
188+
}
189+
}
190+
191+
} // namespace util
192+
193+
autoware_perception_msgs::msg::TrafficSignalArray SignalMatchValidator::validateSignals(
194+
const TrafficSignalArray & perception_signals, const TrafficSignalArray & external_signals)
195+
{
196+
TrafficSignalArray validated_signals;
197+
198+
// Set newer stamp
199+
validated_signals.stamp = util::get_newer_stamp(perception_signals.stamp, external_signals.stamp);
200+
201+
// Create the unique set of the received id,
202+
// then compare the signal element for each received signal id
203+
const auto received_signal_id_set =
204+
util::create_signal_id_set(perception_signals.signals, external_signals.signals);
205+
206+
for (const auto & signal_id : received_signal_id_set) {
207+
const auto perception_result = util::find_signal_by_id(perception_signals, signal_id);
208+
const auto external_result = util::find_signal_by_id(external_signals, signal_id);
209+
210+
// Both results doesn't exist
211+
if (!perception_result && !external_result) {
212+
continue;
213+
}
214+
215+
// We don't validate the pedestrian signals
216+
// TODO(TomohitoAndo): Validate pedestrian signals
217+
if (isPedestrianSignal(signal_id)) {
218+
validated_signals.signals.emplace_back(util::get_highest_confidence_signal(
219+
perception_result, external_result, external_priority_));
220+
221+
continue;
222+
}
223+
224+
// If either of the signal is not received, treat as unknown signal
225+
if (!perception_result && external_result) {
226+
const auto unknown_signal = util::create_unknown_signal(*external_result);
227+
validated_signals.signals.emplace_back(unknown_signal);
228+
continue;
229+
}
230+
if (!external_result && perception_result) {
231+
const auto unknown_signal = util::create_unknown_signal(*perception_result);
232+
validated_signals.signals.emplace_back(unknown_signal);
233+
continue;
234+
}
235+
236+
// Check if they have the same elements
237+
if (!util::are_all_elements_equivalent(
238+
perception_result->elements, external_result->elements)) {
239+
// RCLCPP_WARN_STREAM(rclcpp::get_logger("debug"), "Not the same signal");
240+
241+
const auto unknown_signal = util::create_unknown_signal(*perception_result, *external_result);
242+
validated_signals.signals.emplace_back(unknown_signal);
243+
continue;
244+
}
245+
246+
// Both results are same, then insert the received color
247+
// RCLCPP_WARN_STREAM(rclcpp::get_logger("debug"), "Both results are same");
248+
validated_signals.signals.emplace_back(*perception_result);
249+
}
250+
251+
return validated_signals;
252+
}
253+
254+
void SignalMatchValidator::setPedestrianSignals(
255+
const std::vector<TrafficLightConstPtr> & pedestrian_signals)
256+
{
257+
for (const auto & signal : pedestrian_signals) {
258+
map_pedestrian_signal_regulatory_elements_set_.emplace(signal->id());
259+
}
260+
}
261+
262+
void SignalMatchValidator::setExternalPriority(const bool external_priority)
263+
{
264+
external_priority_ = external_priority;
265+
}
266+
267+
bool SignalMatchValidator::isPedestrianSignal(const lanelet::Id & signal_id)
268+
{
269+
return map_pedestrian_signal_regulatory_elements_set_.find(signal_id) !=
270+
map_pedestrian_signal_regulatory_elements_set_.end();
271+
}

0 commit comments

Comments
 (0)