Skip to content

Commit da0463e

Browse files
Masaya Kataokaclaude
andcommitted
fix(autoware_carla_interface): address Codex review on traffic-light matching
- Use the resolved map origin (`_current_map_origin()`) instead of the raw `map_origin_x/y` parameters when placing CARLA light heads in the map frame, so georeferenced maps (origin derived from the OpenDRIVE geoReference in `on_world_ready`, parameters left at zero) match correctly instead of falling outside the distance threshold and publishing nothing. (P1) - Treat a candidate head as a genuine alternative for the ambiguity test unless its group set is exactly equal to the winner's, replacing the `isdisjoint` check. Overlapping-but-unequal sets (e.g. {500, 501} vs {501}) would otherwise be accepted by arbitrary ranking and publish a missing or spurious group. Adds a regression test. (P2) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Masaya Kataoka <cld-masaya.kataoka@tier4.jp>
1 parent f79e9ef commit da0463e

3 files changed

Lines changed: 25 additions & 15 deletions

File tree

‎simulator/autoware_carla_interface/src/autoware_carla_interface/carla_ros.py‎

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,6 +1225,12 @@ def _carla_light_map_point(self, actor):
12251225
``get_light_boxes()`` reports them in world coordinates) rather than the
12261226
actor origin, which sits at the pole base and is offset from the heads the
12271227
lanelet2 map records. Falls back to the actor location if no boxes exist.
1228+
1229+
The CARLA→map offset is read via :meth:`_current_map_origin` (not the raw
1230+
``map_origin_x/y`` parameters) so georeferenced maps, whose origin is
1231+
derived from the OpenDRIVE geoReference in ``on_world_ready`` while the
1232+
parameters stay at their zero default, transform the heads into the same
1233+
frame as the lanelet2 ``local_x/local_y`` coordinates and localization.
12281234
"""
12291235
try:
12301236
boxes = actor.get_light_boxes()
@@ -1239,11 +1245,8 @@ def _carla_light_map_point(self, actor):
12391245
)
12401246
else:
12411247
carla_location = actor.get_location()
1242-
point = carla_location_to_ros_point(
1243-
carla_location,
1244-
origin_x=self.param_values["map_origin_x"],
1245-
origin_y=self.param_values["map_origin_y"],
1246-
)
1248+
origin_x, origin_y = self._current_map_origin()
1249+
point = carla_location_to_ros_point(carla_location, origin_x=origin_x, origin_y=origin_y)
12471250
return (point.x, point.y)
12481251

12491252
def _parse_traffic_light_id_override(self):

‎simulator/autoware_carla_interface/src/autoware_carla_interface/modules/traffic_light_matcher.py‎

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -193,17 +193,14 @@ def match_traffic_lights(
193193

194194
nearest_dist, nearest_way = ranked[0]
195195
nearest_groups = map_lights.head_groups[nearest_way]
196-
# Closest head that would resolve to a *different* set of group ids, i.e. a
197-
# genuinely different signal (the light across the intersection), not just the
198-
# neighbouring head of the same approach, which shares the same regulatory
199-
# elements and would give the same answer. Only such a head makes a match
200-
# ambiguous.
196+
# Closest head that would resolve to a *different answer* than the winner.
197+
# A head is a genuine alternative unless its group set is exactly equal to
198+
# the winner's: only then does matching it publish the same group ids, so a
199+
# neighbouring head of the same approach is ignored, while a head with an
200+
# overlapping-but-unequal or disjoint set (e.g. {500, 501} vs {501}, or the
201+
# light across the intersection) still makes the match ambiguous.
201202
second_dist = next(
202-
(
203-
d
204-
for d, way_id in ranked[1:]
205-
if map_lights.head_groups[way_id].isdisjoint(nearest_groups)
206-
),
203+
(d for d, way_id in ranked[1:] if map_lights.head_groups[way_id] != nearest_groups),
207204
None,
208205
)
209206

‎simulator/autoware_carla_interface/test/test_traffic_light_matcher.py‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,16 @@ def test_close_neighbor_sharing_groups_is_not_ambiguous():
6666
assert result.assignments["a"] == [1, 2]
6767

6868

69+
def test_overlapping_but_unequal_group_sets_are_ambiguous():
70+
# Two heads at equal distance whose group sets overlap but are not equal:
71+
# matching the wrong one would publish a different set ({500, 501} vs {501}),
72+
# so the light must be dropped, not resolved by arbitrary ranking.
73+
m = _map({"w1": ((0.0, 0.0), {500, 501}), "w2": ((0.5, 0.0), {501})})
74+
result = match_traffic_lights([("a", None, (0.25, 0.0))], m)
75+
assert "a" not in result.assignments
76+
assert _status(result, "a") == MatchResult.AMBIGUOUS
77+
78+
6979
def test_clear_winner_over_nearby_disjoint_head_still_matches():
7080
# Light sits essentially on its own head (0.1 m); a different signal 1.5 m away
7181
# should not defeat the match thanks to the ratio-based ambiguity test.

0 commit comments

Comments
 (0)