diff --git a/CMakeLists.txt b/CMakeLists.txt index 1acc23fcf..3df80bcb6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,8 +74,10 @@ set(OSI_PROTO_FILES osi_trafficlight.proto osi_trafficupdate.proto osi_trafficcommand.proto + osi_referenceline.proto osi_roadmarking.proto osi_lane.proto + osi_logicallane.proto osi_featuredata.proto osi_logicaldetectiondata.proto osi_object.proto diff --git a/doc/images/OSI_LogicalLane1.png b/doc/images/OSI_LogicalLane1.png new file mode 100644 index 000000000..ad13f12d9 Binary files /dev/null and b/doc/images/OSI_LogicalLane1.png differ diff --git a/doc/images/OSI_LogicalLane2.png b/doc/images/OSI_LogicalLane2.png new file mode 100644 index 000000000..f316436e2 Binary files /dev/null and b/doc/images/OSI_LogicalLane2.png differ diff --git a/doc/images/OSI_ReferenceLine1.svg b/doc/images/OSI_ReferenceLine1.svg new file mode 100644 index 000000000..dcd7bc7ea --- /dev/null +++ b/doc/images/OSI_ReferenceLine1.svg @@ -0,0 +1,256 @@ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + P2 + P3 + P1 + + + P4 + + P5 + + + + + + diff --git a/osi_common.proto b/osi_common.proto index 5085541c1..3243a37a7 100644 --- a/osi_common.proto +++ b/osi_common.proto @@ -338,6 +338,55 @@ message Spherical3d optional double elevation = 3; } +// +// \brief Assignment of an object to a logical lane +// +// An object is assigned to a logical lane if it overlaps the logical lane. +// Assignment happens even if the reference point is outside the lane, and only +// a part of the object overlaps (any object overlapping the lane more than 5cm +// has to be assigned to the lane). +// +// As an exception to this, \c TrafficSign and \c TrafficLight are assigned to +// a logical lane if they control traffic on that lane. For \c TrafficSign and +// \c TrafficLight , #s_position refers to the position where the sign or light +// is valid (e.g. where vehicles should stop in case of a red traffic light), +// not the physical position (where the sign or light is in the world). +// Typically, t_position and angle_to_lane do not have any meaning in this +// case, and will be 0. +// +message LogicalLaneAssignment +{ + // ID of the LogicalLane the object is assigned to. + // + // \rules + // refers_to: LogicalLane + // \endrules + // + optional Identifier assigned_lane_id = 1; + + // S position of the object reference point on the lane, in the ST + // coordinate system of the lane. + // + // #s_position might be outside [s_start,s_end] of the lane (and even + // outside [startS,endS] of the reference line) if the reference point is + // outside the lane, but the object overlaps the lane or a TrafficSign or + // TrafficLight is assigned to a lane. + // + optional double s_position = 2; + + // T position of the object reference point on the lane, in the ST + // coordinate system of the lane. + // + optional double t_position = 3; + + // Angle of the object relative to the lane. + // See the ReferenceLine description how the angle is calculated. + // + // Unit: rad + // + optional double angle_to_lane = 4; +} + // // \brief The base attributes of a stationary object or entity. // diff --git a/osi_groundtruth.proto b/osi_groundtruth.proto index 10f9dceae..8b7d8ceb6 100644 --- a/osi_groundtruth.proto +++ b/osi_groundtruth.proto @@ -9,6 +9,8 @@ import "osi_trafficsign.proto"; import "osi_trafficlight.proto"; import "osi_roadmarking.proto"; import "osi_lane.proto"; +import "osi_logicallane.proto"; +import "osi_referenceline.proto"; import "osi_object.proto"; import "osi_occupant.proto"; @@ -171,4 +173,16 @@ message GroundTruth // derives street geometries automatically from a map reference. // optional string model_reference = 16; + + // Reference lines used by LogicalLane + // + repeated ReferenceLine reference_line = 17; + + // Logical lane boundaries used by LogicalLane + // + repeated LogicalLaneBoundary logical_lane_boundary = 18; + + // Logical lanes used e.g. by traffic agents + // + repeated LogicalLane logical_lane = 19; } diff --git a/osi_logicallane.proto b/osi_logicallane.proto new file mode 100644 index 000000000..a0c28f602 --- /dev/null +++ b/osi_logicallane.proto @@ -0,0 +1,821 @@ +syntax = "proto2"; + +option optimize_for = SPEED; + +import "osi_common.proto"; + +package osi3; + +// +// \brief Boundary line of a LogicalLane +// +// Similar to a LaneBoundary, but with a reference line and ST positions. +// +// A logical lane boundary describes the boundary between two logical lanes. As +// such, there will always be exactly one logical lane boundary between two +// lanes at a given S position. Contrary to that, there can be 0 to N physical +// lane boundaries (i.e. type LaneBoundary) between two logical lanes at a +// given S position. +// +// If there are multiple physical lane boundaries at one S position between two +// lanes (think of a solid-broken marking, which would be described by two +// LaneBoundary objects, one for the solid lane marking, one for the broken lane +// marking), then the single LogicalLaneBoundary describing the boundary between +// two logical lanes should be between the physical boundaries. +// +// A logical lane boundary consists of a list of \link LogicalBoundaryPoint +// LogicalBoundaryPoints\endlink. Each point has a XYZ and an ST coordinate. +// The XYZ coordinates describe the position and height of the boundary in the +// world. +// +// Notes on design decisions: +// - The LogicalLaneBoundary has ST coordinates, and is thus a separate type +// from LaneBoundary. +// Advantages of this decision: +// - Calculations like getting the lane width at a position are easy, since +// one can just get the boundary points of the left and right boundary at +// the desired S position (via linear interpolation), and calculate the +// width from the two points. Also getting something like the distance to +// the lane border is very easy. +// - No centerline of the lane is necessary, since this can very easily be +// generated from the boundaries. +// Disadvantages of this decision: +// - %Lane boundaries cannot be shared with physical lanes. This results in +// more data needed. This can mostly be mitigated by only transmitting the +// lane boundaries during initialization (e.g. via the OSMP GroundTruthInit +// message). +// - The LogicalLaneBoundary contains all data directly which an agent model is +// likely to need. It does not include information normally only used by +// sensor models (e.g. the exact length of the color markings on the road). +// This information can be gotten from the physical lane referenced in the +// LogicalLane, if needed. +// +message LogicalLaneBoundary +{ + // The ID of the lane boundary. + // + // \rules + // is_globally_unique + // \endrules + // + optional Identifier id = 1; + + // Points making up the lane boundary. + // + // The boundary must be defined in the same direction as the reference + // line. So S positions should increase along the line. Note that S + // positions will not always increase strictly monotonically. + // Example: + //
+    //                |---------\
+    //                |          \
+    //  /---boundary--|           \\------------
+    // /
+    // ---------- reference line --------------
+    // 
+ // At the place where the boundary suddenly increases, two points will have + // the same S coordinate. + // + // If the boundary approximates a curve (e.g. a cubic function in + // OpenDRIVE), the points must be chosen in a way that the lateral distance + // to the ideal line does not exceed 5cm. As shown in the following image: + // + // \image html line_approximation_error.svg "Approximation error" + // Approximation error green line. + // + // The Z error (difference in Z height between #boundary_line and the + // "real" line) must not exceed 2cm. This is a stricter requirement than + // for errors in the XY plane, because Z differences between lanes + // influence driving very much. + // + // Note: if two lanes have different Z heights (e.g. a driving lane is + // beside a sidewalk, where the sidewalk is 10cm higher than the road), + // then these lanes cannot share a boundary, since their boundaries have + // different Z heights. + // + repeated LogicalBoundaryPoint boundary_line = 2; + + // The reference line for this boundary. + // + // The reference line is used as a coordinate system for this boundary. + // All points of this LogicalLaneBoundary must have S coordinates in the + // range [\c sStart,\c sEnd]. + // + // The reference line should roughly have the same shape as the boundary (so + // roughly parallel to the lane middle), so that S coordinates continually + // increase along the boundary. + // + // \rules + // refers_to: ReferenceLine + // \endrules + // + optional Identifier reference_line_id = 3; + + // Reference to the physical lane boundary or boundaries that make up this + // logical boundary. + // + // Rules and notes: + // - This list is empty if there are no physical lane boundaries to delimit + // a lane. + // - In the common case, this will contain one physical boundary. + // - This list contains several lane boundaries if there are several physical + // lane boundaries at one S position (e.g. both a broken and a solid + // line). + // - If there are several lane boundaries, they must be listed in increasing + // T order (i.e. from right to left in reference line direction). + // Rationale: this makes it easier to determine e.g. rules on lane + // changes, which depend on the T order of the lanes. + // - Whenever physical lane boundaries begin or end, or switch their T + // position (if there are multiple physical lane boundaries), a new + // LogicalLaneBoundary must be created. + // - The referenced LaneBoundary objects may be longer than the + // LogicalLaneBoundary which references them, but must never be shorter. + // + // Example: + //
+    //       Lane 1
+    //  --------a------------------ - - - -c- - - -           ---->
+    //  \- - - -b- - - -
+    //       Lane -1
+    // 
+ // + // This shows the boundary between lane 1 and lane -1, with the reference + // line going from left to right. First there is a solid-broken line (a and + // b), then there is only a solid line (a), then there is a broken line + // (c). There would be three LogicalLaneBoundary objects between Lane1 and + // Lane2: the first would reference first b and then a, the second would + // reference only a, and the third would reference c. + // + // \rules + // refers_to: LaneBoundary + // \endrules + // + repeated Identifier physical_boundary_id = 4; + + // The passing rules, insomuch as they can be determined just from road + // markings. + // + optional PassingRule passing_rule = 5; + + // Optional external reference to the lane boundary source. + // + // \note For OpenDRIVE, there is no direct possibility to reference the + // RoadMark, as there is no unique identifier in this sub-object. + // + // \note For non-ASAM Standards, it is implementation-specific how + // source_reference is resolved. + // + // \note The value has to be repeated because one object may be derived + // from more than one origin source, for example, from a scenario file + // and from sensors. + // + repeated ExternalReference source_reference = 6; + + // + // \brief A point on the boundary + // + message LogicalBoundaryPoint + { + + // The position of the \c LaneBoundaryPoint. + // + optional Vector3d position = 1; + + // S position of the LaneBoundaryPoint, measured along the parent's + // reference_line_id. + // + optional double s_position = 2; + + // T position of the LaneBoundaryPoint, measured along the parent's + // reference_line_id. + // + optional double t_position = 3; + } + + // + // Passing rule of the LogicalLaneBoundary. + // + // This describes how vehicles are legally allowed to move across the + // LogicalLaneBoundary. The PassingRule is determined solely based + // on the semantics of (physical) lane boundaries, not on any signs + // (i.e. it may be overridden by signs). + // + enum PassingRule + { + // Passing rule is unknown (must not be used in ground truth). + // + PASSING_RULE_UNKNOWN = 0; + + // Passing rule fits neither of the other categories. + // + // Example: this type needs to be used if passing depends on the agent + // type, e.g. if cars may change lane, but trucks may not. + // + // This value is also used between LogicalLanes where the traffic + // regulations do not say anything about passing rules (e.g. for a + // LogicalLaneBoundary between LogicalLanes of TYPE_NORMAL + // and TYPE_CURB or between LogicalLanes of TYPE_BORDER and + // TYPE_SHOULDER) . + // + PASSING_RULE_OTHER = 1; + + // No passing is allowed (neither from left to right nor from right to + // left). + // + PASSING_RULE_NONE_ALLOWED = 2; + + // Only passing in increasing T direction allowed. Passing is allowed + // from one lane to the other if the points on the target lane have + // larger T values than points on the source lane (at the same S + // position). In reference line direction (but not necessarily in + // driving direction), this means changing from right to left is + // allowed. + // + PASSING_RULE_INCREASING_T = 3; + + // Only passing in decreasing T direction allowed. Passing is allowed + // from one lane to the other if the points on the target lane have + // smaller T values than points on the source lane (at the same S + // position). In reference line direction (but not necessarily in + // driving direction), this means changing from left to right is + // allowed. + // + PASSING_RULE_DECREASING_T = 4; + + // Passing is allowed in both directions (left to right and right to + // left). + // + PASSING_RULE_BOTH_ALLOWED = 5; + } +} + +// +// \brief A logical lane in the road network. +// +// A logical lane is part of a road. Compared to a physical lane (OSI type +// \c Lane), its existence doesn't hinge on the existence of road markings. So +// e.g. a road with two driving directions but no road markings in-between +// would be presented as two \link LogicalLane LogicalLanes\endlink, but only +// one Lane. So one Lane can consist of multiple \link LogicalLane +// LogicalLanes\endlink. E.g. on intersections, each driving path is one +// LogicalLane, but the whole area is one \c Lane of type \link +// osi3::Lane::Classification::TYPE_INTERSECTION \c TYPE_INTERSECTION \endlink. +// +// Outside of intersections, logical lanes are constructed such that each point on +// the road belongs to at least one (typically: exactly one) logical lane. So +// there are no gaps between logical lanes, and no areas that don't belong to a +// logical lane. +// +// If OSI is generated from OpenDRIVE, then \link LogicalLane +// LogicalLanes\endlink map directly to OpenDRIVE lanes. However, it is allowed +// to merge multiple consecutive (in S direction) OpenDRIVE lanes with the same +// type into one OSI LogicalLane: if an OpenDRIVE lane has a single successor, +// which has the same lane type, and this successor has only one predecessor +// (so no lane merging or splitting) then the two lanes may be presented as one +// continuous LogicalLane. This may be done recursively. +// +// The \link ReferenceLine reference line\endlink pointed to by +// #reference_line_id defines an ST coordinate system for the lane. This ST +// coordinate system is used to describe positions on the lane. +// +// ## Example +// +// The example below shows two logical lanes on an intersection, with a focus +// on the left-turn lane (\c l1): +// \image html OSI_LogicalLane1.png "Two logical lanes on an intersection" +// +// Assumptions not shown in the image: +// - This is right-hand traffic (and thus vehicles on \c l1 drive from the bottom +// to the left, vehicles on \c l2 drive from right to left). +// - The yellow line is a ReferenceLine, defined starting at the bottom, and +// going to the left. +// +// Some features shown in the image relative to \c l1: +// - The yellow line is the ReferenceLine of \c l1 . The ReferenceLine can be +// shared with other lanes. Because the ReferenceLine has the same direction +// as the driving direction of \c l1 in this example, +// #move_direction == #MOVE_DIRECTION_INCREASING_S. +// - The red line marks the area where \c l2 is left of +// \c l1 - this info is recorded in #left_adjacent_lane of \c l1. +// - The red area is the area where \c l2 overlaps \c l1. This is recorded in +// #overlapping_lane of \c l1. +// +// The image below shows the same two lanes, but from the perspective of \c l2: +// \image html OSI_LogicalLane2.png "Two logical lanes on an intersection" +// +// Assumptions not shown in the image: +// - The yellow line is a ReferenceLine, defined starting at the right, going +// to the left. +// +// Some features shown in the image relative to \c l2: +// - The yellow line is the ReferenceLine of \c l2 . The ReferenceLine can be +// shared with other lanes. Because the ReferenceLine has the same direction +// as the driving direction of \c l2 in this example, +// #move_direction == #MOVE_DIRECTION_INCREASING_S. +// - The green line marks the area where \c l1 is right of +// \c l2 - this info is recorded in #right_adjacent_lane of \c l2. +// - The red area is the area where \c l1 overlaps \c l2. This is recorded in +// #overlapping_lane of \c l1. +// +// As can be seen in the images, the two highlighted lanes are neighbours for +// part of their length, but it makes no sense for them to have the same +// reference line, since they diverge significantly. +// +// Note: all the relations shown above are also defined outside of intersections. +// +message LogicalLane +{ + // The ID of the logical lane. + // + // \note Note ID is global unique. + // + // \rules + // is_globally_unique + // \endrules + // + optional Identifier id = 1; + + // The type of the logical lane. + // + optional Type type = 2; + + // Optional external reference to the lane source. + // + // The external reference points to the source of the lane, if it is derived + // from one or more objects or external references. + // + // For example, to reference a lane defined in an OpenDRIVE map + // the items should be set as follows: + // * reference = URI to map, can remain empty if identical with definiton + // in \c GroundTruth::map_reference + // * type = "net.asam.opendrive" + // * identifier[0] = id of t_road + // * identifier[1] = s of t_road_lanes_laneSection + // * identifier[2] = id of t_road_lanes_laneSection_left_lane, + // t_road_lanes_laneSection_right_lane + // + // \note For non-ASAM Standards, it is implementation-specific how + // source_reference is resolved. + // + // \note The value has to be repeated, because one lane segment may be + // derived from more than one origin segment. Multiple sources + // may be added as reference as well, for example, a map and sensors. + // + repeated ExternalReference source_reference = 3; + + // Reference to the physical lanes this logical lane belongs to. + // + // This makes it possible to get detailed information on the physical lane + // properties, e.g. the visual colors of the boundaries, the road + // condition, etc.. + // + // Note: a logical lane may consist of several physical lanes (in a row). + // At any one S position, a logical lane should only reference one physical + // lane. Several logical lanes may reference the same physical lane (see + // drawing below). + // + // Logical lanes should not extend beyond intersections. All logical lanes + // on intersections should end at the latest at the border of the + // intersection. + // + // Example: + //
+    // ---------------------------------
+    //  l1                       l2
+    // ----------    l3        ---------
+    //  l4                       l5
+    // ---------------------------------
+    // 
+ // + // In this case, we have five physical lanes: l1, l2, l4 and l5 where a + // lane marking is present. And l3 is one lane covering the whole road + // (because no road marking is present). + // + // This would typically be presented as two logical lanes: + // - One encompassing l1, part of l3, and l2 + // - The other encompassing l4, part of l3 and l5 + // + // In this example, both logical lanes would reference l3. Their shared + // LogicalLaneBoundary would cut through the middle of l3. + // + // physical_lane_reference does not give any information how much of the + // area of a physical lane is covered by a logical lane. + // + // For LogicalLanes without a correspondence to a Lane.Classification.Subtype + // (i.e. TYPE_MEDIAN, TYPE_CURB, TYPE_TRAM, TYPE_RAIL) this field has no value. + // + // \rules + // refers_to: Lane + // \endrules + // + repeated PhysicalLaneReference physical_lane_reference = 4; + + // The \link ReferenceLine reference line\endlink for this logical lane + // + // The reference line is used as a coordinate system on this lane. + // + // The reference line should roughly have the same shape as the lane, so + // that S coordinates continually increase/decrease along the lane. It is + // not required that the reference line has the same direction as the + // driving direction of the lane. + // + // Neighbouring lanes (i.e. lanes that are neighbours and whose directions + // do not diverge significantly) are strongly encouraged to reference the + // same ReferenceLine, so that vehicles that are next to each other on + // neighbouring lanes have comparable S positions. + // + // The S coordinate of the reference line makes it easy to find e.g. which + // object is next on a lane, using the LogicalLaneAssignment of the + // objects. + // + // The reference trajectory must be sampled such that there are no two + // positions on the lane more than 5cm apart with the same ST coordinate. + // + // \rules + // refers_to: ReferenceLine + // \endrules + // + optional Identifier reference_line_id = 5; + + // Start S position of the lane. + // + // Must be in range [\c sStart,\c sEnd] of the reference line. + // + optional double start_s = 6; + + // End S position of the lane. + // + // Must be in range [\c sStart,\c sEnd] of the reference line. + // + // Requirement: #end_s > #start_s + // + optional double end_s = 7; + + // Definition of the intended driving direction. + // + optional MoveDirection move_direction = 8; + + // Lanes that are directly right of this lane, without gap or overlap. + // + // "Right" is in definition direction (not driving direction), so right lanes + // have smaller T coordinates. + // Entries must be ordered: first by #start_s, then by #end_s. + // + // The XY positions of the polyline generated by the LogicalLaneBoundaries + // of adjacent lanes must match up to a small error (5cm). + // Typically adjacent lanes will share a LogicalLaneBoundary, but this will + // not always be true. Examples: on intersections, it might be hard to generate + // data such that lanes that are adjacent for a short length share a + // LogicalLaneBoundary for this length; also different LogicalLaneBoundaries + // are needed if the lanes have different heights at their boundaries (e.g. + // road adjacent to a sidewalk). + // + repeated LaneRelation right_adjacent_lane = 9; + + // Lanes that are directly left of this lane, without gap or overlap. + // + // "Left" is in definition direction (not driving direction), so left lanes + // have larger T coordinates. + // Entries must be ordered: first by #start_s, then by #end_s. + // + // The XY positions of the polyline generated by the LogicalLaneBoundaries + // of adjacent lanes must match up to a small error (5cm). + // Typically adjacent lanes will share a LogicalLaneBoundary, but this will + // not always be true. Examples: on intersections, it might be hard to generate + // data such that lanes that are adjacent for a short length share a + // LogicalLaneBoundary for this length; also different LogicalLaneBoundaries + // are needed if the lanes have different heights at their boundaries (e.g. + // road adjacent to a sidewalk). + // + repeated LaneRelation left_adjacent_lane = 10; + + // Lanes that partially or completely overlap this lane. + // + // Only overlaps laterally larger than 5cm are considered overlaps for the + // purpose of this relation. + // + // This will typically contain a lot of entries on intersections, but might + // also be used outside of intersections (e.g. if a #TYPE_BIKING lane + // overlaps a #TYPE_NORMAL lane). + // + // Entries must be ordered: first by #start_s, then by #end_s. + // + repeated LaneRelation overlapping_lane = 11; + + // Right boundary of this lane. + // + // References to LogicalLaneBoundary elements. + // All LogicalLaneBoundary elements referenced here must refer to the same + // ReferenceLine as this lane. + // The boundaries together must cover the whole length of the lane (the + // range \[#start_s,#end_s\]) without gap or overlap. The boundaries must be + // stored in ascending order, starting with the smallest S position. + // Consecutive boundaries must share a point: the last point of the + // previous boundary must be identical to the first point of the next + // boundary. + // + // Note: the referenced boundaries may have points outside of + // \[#start_s,#end_s\] (e.g. a boundary may extend beyond the end of a lane). + // + // Note: A curb is a type of LogicalLane and of LaneBoundary. + // If LogicalLane.Type == TYPE_CURB, by convention this + // field references the respective LaneBoundary of TYPE_CURB + // identically to the left_boundary_id of this LogicalLane. + // + // \rules + // refers_to: LogicalLaneBoundary + // \endrules + // + repeated Identifier right_boundary_id = 12; + + // Left boundary of this lane. + // + // References to LogicalLaneBoundary elements. + // All LogicalLaneBoundary elements referenced here must refer to the same + // ReferenceLine as this lane. + // The boundaries together must cover the whole length of the lane (the + // range \[#start_s,#end_s\]) without gap or overlap. The boundaries must be + // stored in ascending order, starting with the smallest S position. + // Consecutive boundaries must share a point: the last point of the + // previous boundary must be identical to the first point of the next + // boundary. + // + // Note: the referenced boundaries may have points outside of + // \[#start_s,#end_s\] (e.g. a boundary may extend beyond the end of a lane). + // + // Note: A curb is a type of LogicalLane and of LaneBoundary. + // If LogicalLane.Type == TYPE_CURB, by convention this + // field references the respective LaneBoundary of TYPE_CURB. + // identically to the right_boundary_id of this LogicalLane. + // + // \rules + // refers_to: LogicalLaneBoundary + // \endrules + // + repeated Identifier left_boundary_id = 13; + + // Lanes that directly are connected to this lane at the beginning. + // + // "Beginning" is relative to the reference line, so connections at #start_s. + // + // Lane predecessors and successors shall only be used to connect lanes if + // a physical connection at the beginning or end of both lanes exist. Both + // lanes have a non-zero width at the connection point and they are + // semantically connected. + // + // A lane may have several predecessors e.g. on intersections, or if a wide + // lane splits into two, or two merge into one. + // + repeated LaneConnection predecessor_lane = 14; + + // Lanes that directly are connected to this lane at the end. + // + // "End" is relative to the reference line, so connections at #end_s. + // + // Lane predecessors and successors shall only be used to connect lanes if + // a physical connection at the beginning or end of both lanes exist. Both + // lanes have a non-zero width at the connection point and they are + // semantically connected. + // + // A lane may have several successors e.g. on intersections, or if a wide + // lane splits into two, or two merge into one. + // + repeated LaneConnection successor_lane = 15; + + // + // Definition of available lane types. + // + // This is mostly aligned with OpenDRIVE, except that lane types modelling + // access restrictions (e.g. "taxi") are not made available here. These are + // already deprecated in OpenDRIVE. To support this, access restrictions + // should be added later, in alignment with OpenDRIVE. + // + enum Type + { + // %Lane of unknown type. Do not use in ground truth. + // + TYPE_UNKNOWN = 0; + + // Any other type of lane. + // + TYPE_OTHER = 1; + + // A normal driving lane. + // Example: Lanes with IDs l1, l2, l3 and l4 in image \ref + // HighwayExit. + // This matches the OpenDRIVE type "driving". + // + // Note: a lane with OpenDRIVE type "bidirectional" will have an OSI + // type of TYPE_NORMAL, with #move_direction == + // #MOVE_DIRECTION_BOTH_ALLOWED. + // + TYPE_NORMAL = 2; + + // A lane that is designated for bicylists. + // Note that biking lanes that cross the road (e.g. on an intersection) + // are also labeled with this type. + // + TYPE_BIKING = 3; + + // A lane that is designated for pedestrians (sidewalk). + // Note that pedestrian lanes that cross the road (e.g. on an + // intersection) are also labeled with this type. + // + TYPE_SIDEWALK = 4; + + // A lane with parking spaces. + // + TYPE_PARKING = 5; + + // A hard shoulder on motorways for emergency stops. + // Example: Lane l5 in image \ref + // HighwayExit. + // + TYPE_STOP = 6; + + // A lane on which cars should not drive. + // + TYPE_RESTRICTED = 7; + + // A hard border on the edge of a road. + // + TYPE_BORDER = 8; + + // A soft border on the edge of a road. + // + TYPE_SHOULDER = 9; + + // A deceleration lane in parallel to the main road. + // Example: Lane l6 in image \ref + // HighwayExit. + // + TYPE_EXIT = 10; + + // An acceleration lane in parallel to the main road. + // + TYPE_ENTRY = 11; + + // A ramp from rural or urban roads joining a motorway. + // + TYPE_ONRAMP = 12; + + // A ramp leading off a motorway onto rural or urban roads. + // + TYPE_OFFRAMP = 13; + + // A ramp that connect two motorways. + // + TYPE_CONNECTINGRAMP = 14; + + // A lane that sits between driving lanes + // that lead in opposite directions. It is + // typically used to separate traffic in + // towns on large roads. + // + TYPE_MEDIAN = 15; + + // Curb stones. Curb stones have a different + // height than the adjacent drivable lanes. + // + TYPE_CURB = 16; + + // A rail lane. This lane covers the area a train needs to drive along + // its rails. + // #overlapping_lane then describes where a train crosses other lanes. + // + TYPE_RAIL = 17; + + // A tram lane. This lane covers the area a tram needs to drive along + // its rails. + // #overlapping_lane then describes where a tram crosses other lanes. + // + TYPE_TRAM = 18; + } + + // + // \brief Reference to a physical lane. + // + message PhysicalLaneReference + { + // Id of the physical lane referenced. + // + // \rules + // refers_to: Lane + // \endrules + // + optional Identifier physical_lane_id = 1; + + // S position on the logical lane where the physical lane starts. + // + optional double start_s = 2; + + // S position on the logical lane where the physical lane ends. + // + // Requirement: #end_s > #start_s + // + optional double end_s = 3; + } + + // + // Describes in which direction moving objects may typically move along a + // lane. + // + // This describes the allowed typical driving direction on a lane, or (in + // the case of pedestrian) the allowed walking direction. + // + // Note: Allowed overtaking (e.g. on country roads) does not automatically + // make a lane bidirectional, since vehicles may normally only drive in the + // other direction during the overtake maneuver, not for longer periods of + // time. + // + enum MoveDirection + { + // Move direction is unknown. Do not use in ground truth. + // + MOVE_DIRECTION_UNKNOWN = 0; + + // Move direction fits neither of the other categories. + // + // Example: a lane where cars may only drive in one direction, but + // bikes may drive in both. + // + MOVE_DIRECTION_OTHER = 1; + + // Objects may move in increasing S direction. + // + // This means they move in the same direction as the reference line. + // + MOVE_DIRECTION_INCREASING_S = 2; + + // Objects may move in decreasing S direction. + // + // This means they move in the opposite direction as the reference line. + // + MOVE_DIRECTION_DECREASING_S = 3; + + // Objects may move in both directions. + // + MOVE_DIRECTION_BOTH_ALLOWED = 4; + } + + // + // \brief Connection to another lane (predecessor or successor) + // + message LaneConnection + { + // Id of the other logical lane that is connected. + // + // \rules + // refers_to: LogicalLane + // \endrules + // + optional Identifier other_lane_id = 1; + + // If true: LaneConnection is at the beginning of the other lane + // If false: LaneConnection is a the end of the other lane + // + optional bool at_begin_of_other_lane = 2; + + } + + // + // \brief Relation of this lane to another logical lane + // + message LaneRelation + { + // Id of the other logical lane. + // + // \rules + // refers_to: LogicalLane + // \endrules + // + optional Identifier other_lane_id = 1; + + // Start s position of the relation. + // + optional double start_s = 2; + + // End s position of the relation. + // + // Requirement: #end_s > #start_s + // + optional double end_s = 3; + + // Start s position of the relation on the other lane. + // + // This is the same place as #start_s, but measured along the reference + // line of the other lane. + // + optional double start_s_other = 4; + + // End s position of the relation on the other lane. + // + // This is the same place as #end_s, but measured along the reference + // line of the other lane. + // + // Note: #end_s_other might be smaller than #start_s_other + // + optional double end_s_other = 5; + } +} + diff --git a/osi_object.proto b/osi_object.proto index 215062706..fc2aa9bde 100644 --- a/osi_object.proto +++ b/osi_object.proto @@ -124,6 +124,12 @@ message StationaryObject // repeated double assigned_lane_percentage = 7; + // Assignment of this object to logical lanes. + // + // \note OSI uses singular instead of plural for repeated field names. + // + repeated LogicalLaneAssignment logical_lane_assignment = 8; + // Definition of object types. // enum Type @@ -696,8 +702,13 @@ message MovingObject // // \note OSI uses singular instead of plural for repeated field names. // - repeated double assigned_lane_percentage = 2; - + repeated double assigned_lane_percentage = 2; + + // Assignment of this object to logical lanes. + // + // \note OSI uses singular instead of plural for repeated field names. + // + repeated LogicalLaneAssignment logical_lane_assignment = 3; } // diff --git a/osi_referenceline.proto b/osi_referenceline.proto new file mode 100644 index 000000000..d8622eeaa --- /dev/null +++ b/osi_referenceline.proto @@ -0,0 +1,207 @@ +syntax = "proto2"; + +option optimize_for = SPEED; + +import "osi_common.proto"; + +package osi3; + +// +// \brief A reference line for defining a non-euclidean ST coordinate system +// +// A reference line is a 3D polyline, used for generating a non-euclidean +// ST coordinate system. +// +// Notes on design decisions: +// - This is a polyline, and not some more complex curve. The advantage of a +// polyline is that it is very simple to generate from various map formats, +// and it is also easy to handle. The downside is that a polyline has no +// direct curvature, and even the angle is not continuous (only C0 smooth). +// In the author's experience, the benefits of a polyline outweigh the costs. +// +message ReferenceLine +{ + // The ID of the logical lane. + // + // \note Note ID is global unique. + // + // \rules + // is_globally_unique + // \endrules + // + optional Identifier id = 1; + + // Points comprising the polyline. + // + // At least 2 points must be given. + // The polyline is defined as the lines between consecutive points. + // Each point has an S coordinate. + // + // ## Rules on the S position + // + // There are a few requirements on the S position: + // - Later points in the list must have strictly larger S coordinates than + // earlier points. + // - For consecutive points, the S difference between them must be at + // least as large as the 2D euclidean distance between the points (2D + // distance == euclidean distance between the points taking only X and Y + // into account). + // - The S distance between two points may be larger than the 2D euclidean + // distance, but should be not much larger. It is allowed to be larger if + // the underlying reference line (e.g. in an OpenDRIVE map) is a curve, + // and thus the sampled reference line has a smaller length than the original + // curve. + // + // Together, these rules allow directly putting OpenDRIVE S coordinates + // into an OSI ReferenceLine. + // + // If the reference line approximates a curve (e.g. a clothoid in + // OpenDRIVE), the points must be chosen in a way that the lateral distance + // to the ideal line does not exceed 5cm. As shown in the following image: + // + // \image html line_approximation_error.svg "Approximation error" + // Approximation error green line. + // + // Between two ReferenceLinePoints, both the world coordinate and the S + // coordinate is interpolated linearly. So each S value uniquely describes + // a point on the polyline. + // + // ## Extending the coordinate system infinitely + // + // For the purpose of this discussion, let's call the S position of the + // first point \c sStart, and the S position of the last point \c sEnd. + // + // For some purposes, S positions outside the normally defined range (i.e. + // outside [\c sStart,\c sEnd]) need to be defined. For this purpose, the + // first line of the polyline is infinitely extended in negative S + // direction. Similarly, the last line of the polyline is infinitely + // extended beyond the last point. The S value of points outside [\c + // sStart,\c sEnd] is defined by the euclidean 2D distance from the start + // or end point, respectively. So if sStart = 15, and a point + // is on the line extended from the start position, with a 2D euclidean + // distance of 10 from the first point, then it has an S position of 5. + // + // A point is "before" the reference line, if its s coordinate is < \c sStart. + // A point is "after" the reference line, if its s coordinate is > \c sEnd. + // + // ## Adding T coordinates + // + // To describe points that are not directly on the polyline, a T coordinate + // is added. T is the signed 2D distance (i.e. hypot(A.X-B.X, + // A.Y-B.Y), if A and B are the two points) between the point to + // describe and the nearest point on the polyline (this point might either + // be on a line segment or at an edge between two line segments). The + // distance is positive if the point is left of the polyline (in definition + // direction), negative if it is right of it. + // The S position of such a point outside the reference line is the same as + // the S value of the nearest point on the polyline. + // + // Notes: + // - The "nearest point on the polyline" is determined in 3D (even if the + // resulting T value is only the 2D distance), in order to choose the + // correct point for 3D curves (think reference lines for roads in parking + // decks). + // - If there are several "nearest points", the one with the smallest S + // coordinate on the polyline is chosen. + // + // ## Defining angles + // + // Sometimes an angle to a reference line is needed. This shall be defined + // as follows: + // First the nearest point on the polyline is determined, as described + // above. If this point is on a line segment, then the angle is calculated + // relative to the line segment on which the reference point lays. + // If the nearest point is at the edge between line segments, then the + // angle of the following line shall be chosen. + // + // ## Converting between world coordinates and ST coordinates + // + // The above rules define an ST coordinate system across the whole XY plane. + // Every XY position has a ST coordinate, but not necessarily a unique ST + // coordinate. + // + // Example: + // \image html OSI_ReferenceLine1.svg + // + // This shows a reference line (consisting of three points), and five points + // not on the reference line. + // + // - For \c P1, the situation is clear, since there is exactly one nearest + // point on the polyline. The resulting ST coordinate uniquely maps back + // to \c P1. + // - \c P2 has multiple points "nearest points" on the polyline. + // As can be seen here, two ST coordinates map to \c P2 (red and grey + // dotted line). Following the rules above, the one with the smallest S + // value is chosen (the red dotted line). + // - \c P3 has a unique "nearest point" on the polyline. However, multiple + // points map to the same ST coordinate as that of \c P3, e.g. \c P4 + // (drawn in grey). + // - Finally, \c P5 shows how the reference line is extended infinitely for + // points that are "outside" the reference line. + // + // The sampling of the polyline must be chosen such that the error + // when converting coordinates is "small enough". The exact needed + // precision is defined for each user, where the reference line is + // referenced. + // + // ## Creating reference lines + // + // When OSI is generated from OpenDRIVE, typically the reference lines will + // be taken directly from the road reference lines in OpenDRIVE, and + // sampled according to the accuracy requirements outlined above. + // + // Other map formats may not have reference lines, so they will have to be + // synthesized by the tool generating OSI data. A few guidelines on this + // process: + // + // - The reference line should follow the road + // - It is preferable to have the reference line in the center of the road + // (e.g. on a highway, it should be in the middle between the two driving + // directions). Rationale: this makes S differences better approximate + // euclidean distances, compared to having the reference line at one side + // of a curvy road. + // + // ## Various notes + // + // Notes on OpenDRIVE compatibility: + // Ideally, one would want the polyline to be fully compatible with + // OpenDRIVE, so that calculations done for OpenDRIVE directly match those + // in OSI. There are a few difficulties with this: + // - The T coordinate is nearly the same as for OpenDRIVE, but + // unfortunately not perfectly. In OpenDRIVE, if the road is tilted using + // superElevation, then the t coordinate system is tilted along, so the T + // coordinate is no longer calculated in the XY plane (as proposed for + // OSI). It doesn't seem feasable to implement the same tilting for OSI, + // so simulation tools will have to consider superElevation and convert + // the T coordinate accordingly: t_OSI = t_OpenDRIVE * + // cos(alpha), where alpha is the superelevation angle. + // - The angle will not be perfectly the same, due to the use of line + // segments in OSI, and curves in OpenDRIVE. In the authors opinion, the + // difference will be negligible if the #poly_line is suitably sampled. + // + // Notes on design decisions: + // - The S coordinate is included directly, both for OpenDRIVE + // compatibility, and to speed up calculations. + // - The rules on S coordinates (e.g. the calculation in 2D space) are + // there to ensure OpenDRIVE compatibility. + // - The rules on T coordinates are there to ensure OpenDRIVE compatibility + // for lanes without superelevation, and to make it easier to convert + // between OSI and OpenDRIVE in case superelevation is present. + // + repeated ReferenceLinePoint poly_line = 2; + + // + // \brief A point on the reference line + // + message ReferenceLinePoint + { + // A world position + // + optional Vector3d world_position = 1; + + // S position on the reference line + // + optional double s_position = 2; + } +} + diff --git a/osi_roadmarking.proto b/osi_roadmarking.proto index 0b9ce9a95..d8ed5a2e0 100644 --- a/osi_roadmarking.proto +++ b/osi_roadmarking.proto @@ -256,6 +256,12 @@ message RoadMarking // optional string sub_code = 11; + // Assignment of this object to logical lanes. + // + // \note OSI uses singular instead of plural for repeated field names. + // + repeated LogicalLaneAssignment logical_lane_assignment = 12; + // Definition of road marking types. // enum Type diff --git a/osi_trafficlight.proto b/osi_trafficlight.proto index ace90bccd..887a99fd4 100644 --- a/osi_trafficlight.proto +++ b/osi_trafficlight.proto @@ -127,6 +127,12 @@ message TrafficLight // optional bool is_out_of_service = 6; + // Assignment of this object to logical lanes. + // + // \note OSI uses singular instead of plural for repeated field names. + // + repeated LogicalLaneAssignment logical_lane_assignment = 7; + // Definition of semantic colors for traffic lights. // // \note The color types represent the semantic classification of a traffic light diff --git a/osi_trafficsign.proto b/osi_trafficsign.proto index 7436e81c0..5be493ebc 100644 --- a/osi_trafficsign.proto +++ b/osi_trafficsign.proto @@ -377,6 +377,13 @@ message TrafficSign // optional string sub_code = 11; + // Assignment of this object to logical lanes. + // + // \note OSI uses singular instead of plural for repeated field + // names. + // + repeated LogicalLaneAssignment logical_lane_assignment = 12; + // Definition of traffic sign types. // Numbers are given according to German StVO. // @@ -5698,6 +5705,13 @@ message TrafficSign // optional string sub_code = 11; + // Assignment of this object to logical lanes. + // + // \note OSI uses singular instead of plural for repeated field + // names. + // + repeated LogicalLaneAssignment logical_lane_assignment = 12; + // Definition of supplementary sign types. // // For general supplementary signs use \c #TYPE_TEXT. diff --git a/setup.py b/setup.py index 70423591e..dcc8ba688 100644 --- a/setup.py +++ b/setup.py @@ -67,6 +67,8 @@ def find_protoc(): 'osi_object.proto', 'osi_occupant.proto', 'osi_lane.proto', + 'osi_logicallane.proto', + 'osi_referenceline.proto', 'osi_sensordata.proto', 'osi_sensorviewconfiguration.proto', 'osi_sensorspecific.proto',