Skip to content

Extracting semantic tags, road and lane types & speed limits#484

Open
aprabou wants to merge 26 commits into
BerkeleyLearnVerify:mainfrom
aprabou:main
Open

Extracting semantic tags, road and lane types & speed limits#484
aprabou wants to merge 26 commits into
BerkeleyLearnVerify:mainfrom
aprabou:main

Conversation

@aprabou

@aprabou aprabou commented Jul 3, 2026

Copy link
Copy Markdown

Description

This extension allows for the extraction of semantic tags and speed limits/types from roads and lanes.
The changes are made to the following files:

roads.py:

  • added distributionFunction speedLimitAt to get the speed limit at coordinate-s along a given range
  • speedLimit element depreciated

xodr_parser.py:

  • Speed parsing/among helpers:

    • speed_to_mps
    • speed_limit_ranges_from_type_records
    • speed_limit_ranges_from_lane_records
    • effective_speed_limit_ranges
    • speed_limit_for_s_interval
    • assign_speed_limit_from_ranges.
  • When an interval straddles multiple limits, the minimum is used and an OpenDriveWarning is emitted.

  • Tag helpers:

    • merge_scenic_tags
    • lane_scenic_tags
    • _junction_tags
    • assign_semantic_tags
  • Propagation helpers:

    • propagate_speed_limit
    • apply_lane_speed_limits
    • propagate_tags
  • Road, Lane, and Junction now capture:

    • type_records
    • lane speed_records
    • junction type_
    • extra_tags
  • Road.toScenicRoad wires per-section and per-lane speed limits and tags into the Scenic objects.

  • Expanded drivable_lane_types / sidewalk_lane_types / shoulder_lane_types defaults (e.g. slipLane, biking, walking, restricted, curb, none; parking classified as a shoulder).

test_opendrive.py:

  • New unit tests covering speed-unit conversion, road/lane speed-range parsing, per-section and per-lane effective limits, multi-limit warnings, and tag propagation

Checklist

  • I have tested the changes locally via pytest and/or other means
  • I have added or updated relevant documentation
  • I have autoformatted the code with black and isort
  • I have added test cases (if applicable)

@dfremont dfremont self-requested a review July 6, 2026 21:26
Comment thread src/scenic/domains/driving/roads.py Outdated
Comment thread src/scenic/formats/opendrive/xodr_parser.py
Comment thread src/scenic/formats/opendrive/xodr_parser.py Outdated
Comment thread src/scenic/formats/opendrive/xodr_parser.py Outdated
Comment thread src/scenic/formats/opendrive/xodr_parser.py
Comment thread src/scenic/formats/opendrive/xodr_parser.py Outdated
Comment thread src/scenic/formats/opendrive/xodr_parser.py
Comment thread src/scenic/formats/opendrive/xodr_parser.py Outdated
Comment thread src/scenic/formats/opendrive/xodr_parser.py Outdated
Comment thread src/scenic/formats/opendrive/xodr_parser.py Outdated
Comment thread src/scenic/formats/opendrive/xodr_parser.py Outdated
Comment thread src/scenic/formats/opendrive/xodr_parser.py Outdated
Comment thread src/scenic/formats/opendrive/xodr_parser.py Outdated
Comment thread src/scenic/formats/opendrive/xodr_parser.py Outdated
Comment thread src/scenic/formats/opendrive/xodr_parser.py Outdated
Comment thread src/scenic/formats/opendrive/xodr_parser.py Outdated
Comment thread src/scenic/formats/opendrive/xodr_parser.py Outdated
Comment thread src/scenic/formats/opendrive/xodr_parser.py Outdated
Comment thread src/scenic/formats/opendrive/xodr_parser.py Outdated
Comment thread src/scenic/formats/opendrive/xodr_parser.py Outdated
Comment thread src/scenic/formats/opendrive/xodr_parser.py Outdated
Comment thread src/scenic/formats/opendrive/xodr_parser.py Outdated
Comment thread src/scenic/formats/opendrive/xodr_parser.py Outdated
Comment thread src/scenic/formats/opendrive/xodr_parser.py Outdated
Comment thread tests/formats/opendrive/test_opendrive.py Outdated
Comment thread tests/formats/opendrive/test_opendrive.py Outdated
Comment thread tests/formats/opendrive/test_opendrive.py Outdated

@dfremont dfremont left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is definitely headed in the right direction, thanks Ashwin! I think we can simplify the code a lot, though: see the comments above. Here are a few other suggestions:

  • Let's add a Network.speedLimitAt method to get the speed limit (if any) at a given point. I think it can just call Network.laneSectionAt to get the lane section, compute s in the same way that the first line of PolylineRegion.nearestSegmentTo does (only necessary if there's more than 1 speed limit range), and then look up the right speed limit range.
  • I haven't finished reading all the tests yet (I'll wait until you refactor things), but they're pretty verbose: please see if you can simplify the code. One note is that I don't think we need unit tests for things like propagate_speed_limit: that's an internal function which could easily get refactored away. I'd rather have integration tests which load a simple map and then assert things about the resulting Network object. (Of course, for functions that will be used in many places and are easily testable on their own, unit tests make sense.)

@aprabou

aprabou commented Jul 13, 2026

Copy link
Copy Markdown
Author

Thank you again for the detailed comments and proposed changes. A lot of what was done was refactoring / removing unnecessary checks, but here are the major changes:

  • Changes dealing with None values:
    • _speed_limit_ranges_from_s_speed_records: removed current_speed inheritance. Each record now has its own speed_mps which can be None. Also added a prepend record starting at 0.0, so coverage always starts at s = 0, if the first record has s > 0.
    • speed_limit_ranges_from_type_records: no more inheritance across types, allows for None speeds.
    • assign_speed_limit_from_ranges: if None gaps exist, it is kept track of rather than discarded.
    • speed_limit_for_s_interval: interval overlapping only undefined stretches returns None.
  • Add NetworkElement.speedLimitAt(s) and Network.speedLimitAt(point) to look up the limit at an arc-length or world point (via the containing lane section).
  • Propagate semantic tags from road types and junction types onto roads / road sections / lane groups; lanes and lane sections get their OpenDRIVE lane type as tags.
  • Split OpenDRIVE coverage into test_speeds.py and test_tags.py (shared helpers in conftest.py).
  • Cover unit conversion, road/lane range parsing, lane override, multi-limit warnings, None/no-limit ranges, Network.speedLimitAt, and tag propagation on synthetic maps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants