Roundabout elements
A roundabout is a circular unidirectional route with standardized entry and exit behavior.
- All entries originate from the roundabout's external side and lead into it.
- All exits lead from the roundabout to the external network.
- By default, entry paths do not conflict with exit paths.
In terms of other route elements, the roundabout can be viewed as a set of junctions. Each junction in the roundabout includes the following elements:
- One incoming one_way_road, R_i, from the roundabout.
- One outgoing one_way_road, R_o, into the roundabout .
- An internal_road connecting R_i to R_o.
- At most one entry one_way_road, R_n, connected by an internal_road to R_o.
- At most one exit one_way_road, R_x, connected by an internal_road from R_i.
- By default the internal_road connecting R_n to R_o does not intersect with the internal_road connecting R_i to R_x, though this property can be modified by configuration variable top.config.map.roundabout_allow_entry_exit_conflict (default is false).
- The junction may have additional internal_road elements that are not a part of the roundabout.
Four route element types are used to model roundabouts:
roundabout_entry- an entry path into the roundabout.roundabout_from_entry- a route originating from aroundabout_entrythat completes one full round of the roundabout.roundabout_exit- an exit path from the roundabout.roundabout_to_exit- a route leading to aroundabout_exitthat completes one full round of the roundabout.
roundabout_entry
The roundabout_entry element represents an entry into a roundabout. It is congruent with an internal_road connecting some R_n to some R_o (see roles of R_n and R_o one_way_roads defined above).
The roundabout entries are indexed from 0 to the to number_of_entries - 1, in increasing order according to the driving direction. The entry with index 0 is chosen arbitrarily. In some cases, a single roundabout entry may be modeled by multiple roundabout_entry elements. For example, see the bottom (south) entry in the image. This can occur when the source map models multiple entry lanes of a single entry as separate roads. All roundabout_entry elements that are part of the same entry share the same entry index, entry_idx.
OSC definition of roundabout_entry
# A roundabout_entry is a road element that represents an entry into a roundabout.
# It is congruent with an internal_road that enters the roundabout.
#
struct roundabout_entry inherits road_element:
# ID of the roundabout. All roundabout_entry, roundabout_from_entry, roundabout_exit and roundabout_to_exit
# elements of a given roundabout have the same roundabout_id.
#
roundabout_id: uint
# ID of the internal_road congruent with this instance.
#
internal_road_id: uint
# ID of the roundabout_from_entry instance immediately following this instance.
#
roundabout_from_entry_id: uint
# Index of the entry (from 0 to total_entries-1).
#
entry_idx: uint
# Index of the first exit following this entry.
#
first_exit_idx: uint
# The same as in_junction_yaw of the one_way_road leading to this internal_road.
#
in_yaw: angle
# The number of entries in the roundabout.
#
total_entries: uint
# The number of exits in the roundabout.
#
total_exits: uint
roundabout_from_entry
The roundabout_from_entry element represents a circular route that begins at the end of a roundabout_entry and completes exactly one full cycle around the roundabout. There is a one-to-one relationship between roundabout_entry elements and their corresponding roundabout_from_entry elements.
The image below highlights the roundabout_from_entry elements of a single roundabout. Since they overlap, a single instance is outlined in yellow for illustration.
The roundabout_from_entry element specifies the number of lanes at the beginning of its route.
OSC definition of roundabout_from_entry
# A roundabout_from_entry is a road element that represents a circular route around a roundabout, starting from some
# roundabout_entry.
#
struct roundabout_from_entry inherits road_element:
# ID of the roundabout. All roundabout_entry, roundabout_from_entry, roundabout_exit and roundabout_to_exit
# elements of a given roundabout have the same roundabout_id.
#
roundabout_id: uint
# ID of the roundabout_entry instance leading to this.
#
roundabout_entry_id: uint
# The number of lanes at the beginning of this route.
#
num_lanes: uint
roundabout_exit
The roundabout_exit element represents an exit from a roundabout. It is congruent with an internal_road connecting some R_i to some R_x (see the roles of R_i and R_x one_way_roads defined above).
Roundabout exits are indexed from 0 to the to number_of_exits - 1, in increasing order according to the driving direction. The exit with index 0 is chosen arbitrarily. In some cases, a single roundabout exit may be modeled by multiple roundabout_exit elements. This can happen when the source map models multiple exit lanes of a single exit as separate roads. All roundabout_exit elements that belong to the same exit share the same exit index, exit_idx.
OSC definition of roundabout_exit
# A roundabout_exit is a road element that represents an exit from a roundabout.
# It is congruent with an internal_road that exits the roundabout.
#
struct roundabout_exit inherits road_element:
# ID of the roundabout. All roundabout_entry, roundabout_from_entry, roundabout_exit and roundabout_to_exit
# elements of a given roundabout have the same roundabout_id.
#
roundabout_id: uint
# ID of the internal_road congruent with this instance.
#
internal_road_id: uint
# ID of the roundabout_to_exit instance that this instance immediately follows.
#
roundabout_to_exit_id: uint
# Index of the exit (from 0 to total_exits-1).
#
exit_idx: uint
# Index of the first entry preceding this exit.
#
first_entry_idx: uint
# The same as out_junction_yaw of the one_way_road that follows this internal_road.
#
out_yaw: angle
# The number of exits in the roundabout.
#
total_exits: uint
# The number of entries in the roundabout.
#
total_entries: uint
roundabout_to_exit
The roundabout_to_exit element represents a circular route that ends at the start of some roundabout_exit and completes exactly one full cycle around the roundabout. There is a one-to-one relation between rounabout_exit elements and their corresponding roundabout_to_exit elements.
The image below highlights the roundabout_from_exit elements of a single roundabout. Since they overlap, a single instance is outlined in red for illustration.
The roundabout_to_exit element specifies the number of lanes at the end of its route.
OSC definition of roundabout_to_exit
# A roundabout_to_exit is a road element that represents a circular route around a roundabout, ending at some
# roundabout_exit.
#
struct roundabout_to_exit inherits road_element:
# ID of the roundabout. All roundabout_entry, roundabout_from_entry, roundabout_exit and roundabout_to_exit
# elements of a given roundabout have the same roundabout_id.
#
roundabout_id: uint
# ID of the roundabout_exit instance that follows this.
#
roundabout_exit_id: uint
# The number of lanes at the end of this route.
#
num_lanes: uint
Roundabout modifiers and methods
roundabout_entry_exit_direction
This modifier and method that captures the relative direction between a roundabout_entry and a roundabout_exit. Direction can be expressed in terms of the enum roundabout_drive_direction, which divides the circle into eight 45-degree slices:
# 8 possible drive directions at a roundabout, 45 degree angle range for each direction
#
enum roundabout_drive_direction: [not_defined, slight_left, left, sharp_left, slight_right, right, sharp_right, full_circle, straight]
modifier top.roundabout_entry_exit_direction
Constrains the direction between a roundabout entry and a roundabout_exit.
# Constrains the direction between a roundabout-entry and a roundabout-exit
#
modifier top.roundabout_entry_exit_direction:
# Entry to roundabout R
#
entry: roundabout_entry
# Exit from roundabout R
#
exit: roundabout_exit
# Relative direction between entry and exit in terms of `roundabout_drive_direction`
#
relative_direction: roundabout_drive_direction
# Relative direction between entry and exit in terms of angle difference
#
angle_diff: angle
method map.get_roundabout_entry_exit_direction
Returns the relative direction between a roundabout_entry and a roundabout_exit in terms of enum roundabout_drive_direction.
extend map:
# Returns the relative direction between a roundabout-entry and a roundabout-exit
# If the entry and exit are not in the same roundabout, then the direction is 'not_defined'
#
def get_roundabout_entry_exit_direction(entry: roundabout_entry, exit: roundabout_exit) \
-> roundabout_drive_direction is undefined
Parameters
- entry - a roundabout_entry
- exit - a roundabout_exit
Return
The relative direction between an entry and an exit. If the entry and exit are not in the same roundabout, then the direction is 'not_defined'.
roundabout_entry_to_exit_relation
Modifier and method that captures the relation between a roundabout entry and exit in terms of the number of exits following the entry. Given a roundabout entry, exit number 1 denotes the first exit after entry, 2 denotes the second exit, 3 the third exit, and so on.
modifier top.roundabout_entry_to_exit_relation
Constrains the relationship between a roundabout entry and a roundabout exit in terms of the number of exits following the entry.
# Constrains the relation between a roundabout-entry and a roundabout-exit in terms of number of subsequent exits
#
modifier top.roundabout_entry_to_exit_relation:
# A roundabout entry ('entry' and 'exit' are in the same roundabout)
#
entry: roundabout_entry
# A roundabout exit ('entry' and 'exit' are in the same roundabout)
#
exit: roundabout_exit
# 'exit_number' is 1 for the first exit following 'entry', 2 for the second exit following 'entry',
# etc, in [1..total_exits].
#
exit_number: uint
method map.get_exit_number_relative_to_entry
Gets the order of a roundabout exit relative to a given roundabout entry.
extend map:
# Returns the number of exits between the entry and the exit in driving direction (1 for the first exit).
# If the entry and exit are not in the same roundabout, then 0 is returned.
#
def get_exit_number_relative_to_entry(entry: roundabout_entry, exit: roundabout_exit) -> uint is undefined
Parameters
- entry - a roundabout_entry
- exit - a roundabout_exit
Return
The order of exit relative to entry. 1 for the first exit, 2 for the second exit, and so on. If entry and exit are not in the same roundabout then 0 is returned. The retun value is in the range [0..total_exits].
modifier top.roundabout_entry_to_entry_relation
Constrains the relationship between two roundabout entries in terms of number of subsequent entries.
# Constrains the relation between two roundabout-entries in terms of number of subsequent entries.
#
modifier top.roundabout_entry_to_entry_relation:
# First roundabout entry ('first_entry' and 'second_entry' are in the same roundabout)
#
first_entry: roundabout_entry
# Second roundabout entry ('first_entry' and 'second_entry' are in the same roundabout)
#
second_entry: roundabout_entry
# The number of entries between the first and second entry, in [0..total_entries-1].
# If 'entry_number' is 0, then 'second_entry' is the same as 'first_entry', otherwise it is the
# next * 'entry_number' entry in driving direction.
#
entry_number: uint
Example OSC2 scenario using roundabout elements and modifiers
In this scenario, the Ego enters the roundabout and takes the second exit. In parallel, another vehicle enters the roundabout one entry before the Ego and takes the same exit as the Ego. During the scenario, a stationary pedestrian is positioned on the right edge of the roundabout, 10 meters ahead of the Ego's entry.
import "$FTX/env/basic/exe_platforms/model_ssp/config/model_sumo_config.osc"
extend test_config:
set map = "$FTX/packages/maps/M348_FTX_Roundabouts.xodr"
# Example scenario utilizing various roundabout elements and modifiers:
# - The Ego enters the roundabout and takes the second exit.
# - In parallel another vehicle enters the roundabout, one entry before the Ego and takes the same exit as the Ego.
# - During the scenario, a stationary pedestrian is placed on the right edge of the roundabout, 10 meters ahead of the Ego's entry.
extend top.main:
# Entry to a roundabout with more entries than exits
sut_ra_entry: roundabout_entry with:
keep(it.total_entries > it.total_exits)
# Exit from the roundabout
sut_ra_exit: roundabout_exit
# Define the relation between the entry and exit
roundabout_entry_to_exit_relation(sut_ra_entry, sut_ra_exit, 2)
# NPC enters the roundabout from the first entry before SUT
npc_ra_entry: roundabout_entry with:
keep(it.roundabout_id == sut_ra_entry.roundabout_id)
# Define the relation between the NPC's entry and the SUT's entry
roundabout_entry_to_entry_relation(first_entry: npc_ra_entry, second_entry: sut_ra_entry, entry_number: 1)
# NPC vehicle
npc: vehicle with:
keep(it.vehicle_category == sedan)
# Static person object
static_person: plain_object with:
keep(it.kind == person)
# Circular route starting at the SUT's entry
roundabout_route: roundabout_from_entry with:
keep(it.roundabout_entry_id == sut_ra_entry.id)
# Position for the static person
person_position: msp_position
# Constrain the position of the static person to be 10m ahead of the SUT's entry.
position_along_road(person_position, roundabout_route, lon_offset:10m, rightmost_lane: true, lat_reference: right)
do parallel(duration: [10..40]s, overlap: equal):
serial():
# Place the static person at the position
static_person.exists_at(person_position)
serial():
# SUT drive before roundabout
sut.car.drive(duration: 2s)
# SUT drive into and out of the roundabout
sut.car.drive() with:
# drive into the roundabout
along(sut_ra_entry, at: start)
# drive out of the roundabout
along(sut_ra_exit, at: end)
# SUT drive after roundabout
sut.car.drive(duration: [2..10]s)
serial():
# NPC drive before roundabout
npc.drive(duration: 1s)
# NPC drive into and out of the roundabout
npc.drive() with:
# drive into the roundabout
along(npc_ra_entry, at: start)
# drive out of the roundabout
along(sut_ra_exit, at: end)
# NPC drive after roundabout
npc.drive(duration: [2..10]s)