Intersection

In this example we demonstrate how to define a T-shape intersection with AutomotiveSimulator. You will also learn how to define your own custom action type and driver model type.

Generate a T-Shape intersection

In order to generate the road network, we first initialize a Roadway object.

using AutomotiveSimulator
using AutomotiveVisualization
using Random

roadway = Roadway()

Define coordinates of the entry and exit points to the intersection

r = 5.0 # turn radius
w = DEFAULT_LANE_WIDTH

A = VecSE2(0.0,w,-π)
B = VecSE2(0.0,0.0,0.0)
C = VecSE2(r,-r,-π/2)
D = VecSE2(r+w,-r,π/2)
E = VecSE2(2r+w,0,0)
F = VecSE2(2r+w,w,-π)

The next step consists in appending all the lanes to the road network. We can define a helper function to add a new lane to the roadway.

function append_to_curve!(target::Curve, newstuff::Curve)
    s_end = target[end].s
    for c in newstuff
        push!(target, CurvePt(c.pos, c.s+s_end, c.k, c.kd))
    end
    return target
end

Example of a lane that consists of 3 road segments, a straight curve (from the left to the center), a turning part (right turn) and a final straight curve.

Append right turn coming from the left

curve = gen_straight_curve(convert(VecE2, B+VecE2(-100,0)), convert(VecE2, B), 2)
append_to_curve!(curve, gen_bezier_curve(B, C, 0.6r, 0.6r, 51)[2:end])
append_to_curve!(curve, gen_straight_curve(convert(VecE2, C), convert(VecE2, C+VecE2(0,-50.0)), 2))
lane = Lane(LaneTag(length(roadway.segments)+1,1), curve)
push!(roadway.segments, RoadSegment(lane.tag.segment, [lane]))
1-element Vector{RoadSegment{Float64}}:
 RoadSegment{Float64}(1, Lane{Float64}[Lane{Float64}(LaneTag(1, 1), CurvePt{Float64}[CurvePt({-100.000, 0.000, 0.000}, 0.000, 0.000, NaN), CurvePt({0.000, 0.000, 0.000}, 100.000, 0.000, NaN), CurvePt({0.179, -0.002, -0.027}, 100.179, -0.153, NaN), CurvePt({0.355, -0.010, -0.054}, 100.355, -0.157, NaN), CurvePt({0.529, -0.021, -0.082}, 100.530, -0.162, NaN), CurvePt({0.700, -0.038, -0.110}, 100.702, -0.166, NaN), CurvePt({0.869, -0.059, -0.139}, 100.872, -0.171, NaN), CurvePt({1.035, -0.085, -0.168}, 101.040, -0.175, NaN), CurvePt({1.198, -0.115, -0.198}, 101.206, -0.180, NaN), CurvePt({1.359, -0.150, -0.227}, 101.370, -0.184, NaN)  …  CurvePt({4.885, -3.802, -1.373}, 106.755, -0.180, NaN), CurvePt({4.915, -3.965, -1.403}, 106.921, -0.175, NaN), CurvePt({4.941, -4.131, -1.432}, 107.089, -0.171, NaN), CurvePt({4.962, -4.300, -1.461}, 107.259, -0.166, NaN), CurvePt({4.979, -4.471, -1.489}, 107.431, -0.162, NaN), CurvePt({4.990, -4.645, -1.517}, 107.605, -0.157, NaN), CurvePt({4.998, -4.821, -1.544}, 107.782, -0.153, NaN), CurvePt({5.000, -5.000, -1.571}, 107.961, -0.148, NaN), CurvePt({5.000, -5.000, -1.571}, 107.961, 0.000, NaN), CurvePt({5.000, -55.000, -1.571}, 157.961, 0.000, NaN)], 3.0, SpeedLimit(-Inf, Inf), LaneBoundary(:unknown, :unknown), LaneBoundary(:unknown, :unknown), LaneConnection{Int64, Float64}[], LaneConnection{Int64, Float64}[])])

visualize the current lane constellation

snapshot = render([roadway])

partial intersection

Let's repeat the process and complete the T-shape intersection

Append straight left

curve = gen_straight_curve(convert(VecE2, B+VecE2(-100,0)), convert(VecE2, B), 2)
append_to_curve!(curve, gen_straight_curve(convert(VecE2, B), convert(VecE2, E), 2)[2:end])
append_to_curve!(curve, gen_straight_curve(convert(VecE2, E), convert(VecE2, E+VecE2(50,0)), 2))
lane = Lane(LaneTag(length(roadway.segments)+1,1), curve)
push!(roadway.segments, RoadSegment(lane.tag.segment, [lane]))
2-element Vector{RoadSegment{Float64}}:
 RoadSegment{Float64}(1, Lane{Float64}[Lane{Float64}(LaneTag(1, 1), CurvePt{Float64}[CurvePt({-100.000, 0.000, 0.000}, 0.000, 0.000, NaN), CurvePt({0.000, 0.000, 0.000}, 100.000, 0.000, NaN), CurvePt({0.179, -0.002, -0.027}, 100.179, -0.153, NaN), CurvePt({0.355, -0.010, -0.054}, 100.355, -0.157, NaN), CurvePt({0.529, -0.021, -0.082}, 100.530, -0.162, NaN), CurvePt({0.700, -0.038, -0.110}, 100.702, -0.166, NaN), CurvePt({0.869, -0.059, -0.139}, 100.872, -0.171, NaN), CurvePt({1.035, -0.085, -0.168}, 101.040, -0.175, NaN), CurvePt({1.198, -0.115, -0.198}, 101.206, -0.180, NaN), CurvePt({1.359, -0.150, -0.227}, 101.370, -0.184, NaN)  …  CurvePt({4.885, -3.802, -1.373}, 106.755, -0.180, NaN), CurvePt({4.915, -3.965, -1.403}, 106.921, -0.175, NaN), CurvePt({4.941, -4.131, -1.432}, 107.089, -0.171, NaN), CurvePt({4.962, -4.300, -1.461}, 107.259, -0.166, NaN), CurvePt({4.979, -4.471, -1.489}, 107.431, -0.162, NaN), CurvePt({4.990, -4.645, -1.517}, 107.605, -0.157, NaN), CurvePt({4.998, -4.821, -1.544}, 107.782, -0.153, NaN), CurvePt({5.000, -5.000, -1.571}, 107.961, -0.148, NaN), CurvePt({5.000, -5.000, -1.571}, 107.961, 0.000, NaN), CurvePt({5.000, -55.000, -1.571}, 157.961, 0.000, NaN)], 3.0, SpeedLimit(-Inf, Inf), LaneBoundary(:unknown, :unknown), LaneBoundary(:unknown, :unknown), LaneConnection{Int64, Float64}[], LaneConnection{Int64, Float64}[])])
 RoadSegment{Float64}(2, Lane{Float64}[Lane{Float64}(LaneTag(2, 1), CurvePt{Float64}[CurvePt({-100.000, 0.000, 0.000}, 0.000, 0.000, NaN), CurvePt({0.000, 0.000, 0.000}, 100.000, 0.000, NaN), CurvePt({13.000, 0.000, 0.000}, 113.000, 0.000, NaN), CurvePt({13.000, 0.000, 0.000}, 113.000, 0.000, NaN), CurvePt({63.000, 0.000, 0.000}, 163.000, 0.000, NaN)], 3.0, SpeedLimit(-Inf, Inf), LaneBoundary(:unknown, :unknown), LaneBoundary(:unknown, :unknown), LaneConnection{Int64, Float64}[], LaneConnection{Int64, Float64}[])])

Append straight right

curve = gen_straight_curve(convert(VecE2, F+VecE2(50,0)), convert(VecE2, F), 2)
append_to_curve!(curve, gen_straight_curve(convert(VecE2, F), convert(VecE2, A), 2)[2:end])
append_to_curve!(curve, gen_straight_curve(convert(VecE2, A), convert(VecE2, A+VecE2(-100,0)), 2))
lane = Lane(LaneTag(length(roadway.segments)+1,1), curve)
push!(roadway.segments, RoadSegment(lane.tag.segment, [lane]))
3-element Vector{RoadSegment{Float64}}:
 RoadSegment{Float64}(1, Lane{Float64}[Lane{Float64}(LaneTag(1, 1), CurvePt{Float64}[CurvePt({-100.000, 0.000, 0.000}, 0.000, 0.000, NaN), CurvePt({0.000, 0.000, 0.000}, 100.000, 0.000, NaN), CurvePt({0.179, -0.002, -0.027}, 100.179, -0.153, NaN), CurvePt({0.355, -0.010, -0.054}, 100.355, -0.157, NaN), CurvePt({0.529, -0.021, -0.082}, 100.530, -0.162, NaN), CurvePt({0.700, -0.038, -0.110}, 100.702, -0.166, NaN), CurvePt({0.869, -0.059, -0.139}, 100.872, -0.171, NaN), CurvePt({1.035, -0.085, -0.168}, 101.040, -0.175, NaN), CurvePt({1.198, -0.115, -0.198}, 101.206, -0.180, NaN), CurvePt({1.359, -0.150, -0.227}, 101.370, -0.184, NaN)  …  CurvePt({4.885, -3.802, -1.373}, 106.755, -0.180, NaN), CurvePt({4.915, -3.965, -1.403}, 106.921, -0.175, NaN), CurvePt({4.941, -4.131, -1.432}, 107.089, -0.171, NaN), CurvePt({4.962, -4.300, -1.461}, 107.259, -0.166, NaN), CurvePt({4.979, -4.471, -1.489}, 107.431, -0.162, NaN), CurvePt({4.990, -4.645, -1.517}, 107.605, -0.157, NaN), CurvePt({4.998, -4.821, -1.544}, 107.782, -0.153, NaN), CurvePt({5.000, -5.000, -1.571}, 107.961, -0.148, NaN), CurvePt({5.000, -5.000, -1.571}, 107.961, 0.000, NaN), CurvePt({5.000, -55.000, -1.571}, 157.961, 0.000, NaN)], 3.0, SpeedLimit(-Inf, Inf), LaneBoundary(:unknown, :unknown), LaneBoundary(:unknown, :unknown), LaneConnection{Int64, Float64}[], LaneConnection{Int64, Float64}[])])
 RoadSegment{Float64}(2, Lane{Float64}[Lane{Float64}(LaneTag(2, 1), CurvePt{Float64}[CurvePt({-100.000, 0.000, 0.000}, 0.000, 0.000, NaN), CurvePt({0.000, 0.000, 0.000}, 100.000, 0.000, NaN), CurvePt({13.000, 0.000, 0.000}, 113.000, 0.000, NaN), CurvePt({13.000, 0.000, 0.000}, 113.000, 0.000, NaN), CurvePt({63.000, 0.000, 0.000}, 163.000, 0.000, NaN)], 3.0, SpeedLimit(-Inf, Inf), LaneBoundary(:unknown, :unknown), LaneBoundary(:unknown, :unknown), LaneConnection{Int64, Float64}[], LaneConnection{Int64, Float64}[])])
 RoadSegment{Float64}(3, Lane{Float64}[Lane{Float64}(LaneTag(3, 1), CurvePt{Float64}[CurvePt({63.000, 3.000, 3.142}, 0.000, 0.000, NaN), CurvePt({13.000, 3.000, 3.142}, 50.000, 0.000, NaN), CurvePt({0.000, 3.000, 3.142}, 63.000, 0.000, NaN), CurvePt({0.000, 3.000, 3.142}, 63.000, 0.000, NaN), CurvePt({-100.000, 3.000, 3.142}, 163.000, 0.000, NaN)], 3.0, SpeedLimit(-Inf, Inf), LaneBoundary(:unknown, :unknown), LaneBoundary(:unknown, :unknown), LaneConnection{Int64, Float64}[], LaneConnection{Int64, Float64}[])])

Append left turn coming from the right

curve = gen_straight_curve(convert(VecE2, F+VecE2(50,0)), convert(VecE2, F), 2)
append_to_curve!(curve, gen_bezier_curve(F, C, 0.9r, 0.9r, 51)[2:end])
append_to_curve!(curve, gen_straight_curve(convert(VecE2, C), convert(VecE2, C+VecE2(0,-50)), 2))
lane = Lane(LaneTag(length(roadway.segments)+1,1), curve)
push!(roadway.segments, RoadSegment(lane.tag.segment, [lane]))
4-element Vector{RoadSegment{Float64}}:
 RoadSegment{Float64}(1, Lane{Float64}[Lane{Float64}(LaneTag(1, 1), CurvePt{Float64}[CurvePt({-100.000, 0.000, 0.000}, 0.000, 0.000, NaN), CurvePt({0.000, 0.000, 0.000}, 100.000, 0.000, NaN), CurvePt({0.179, -0.002, -0.027}, 100.179, -0.153, NaN), CurvePt({0.355, -0.010, -0.054}, 100.355, -0.157, NaN), CurvePt({0.529, -0.021, -0.082}, 100.530, -0.162, NaN), CurvePt({0.700, -0.038, -0.110}, 100.702, -0.166, NaN), CurvePt({0.869, -0.059, -0.139}, 100.872, -0.171, NaN), CurvePt({1.035, -0.085, -0.168}, 101.040, -0.175, NaN), CurvePt({1.198, -0.115, -0.198}, 101.206, -0.180, NaN), CurvePt({1.359, -0.150, -0.227}, 101.370, -0.184, NaN)  …  CurvePt({4.885, -3.802, -1.373}, 106.755, -0.180, NaN), CurvePt({4.915, -3.965, -1.403}, 106.921, -0.175, NaN), CurvePt({4.941, -4.131, -1.432}, 107.089, -0.171, NaN), CurvePt({4.962, -4.300, -1.461}, 107.259, -0.166, NaN), CurvePt({4.979, -4.471, -1.489}, 107.431, -0.162, NaN), CurvePt({4.990, -4.645, -1.517}, 107.605, -0.157, NaN), CurvePt({4.998, -4.821, -1.544}, 107.782, -0.153, NaN), CurvePt({5.000, -5.000, -1.571}, 107.961, -0.148, NaN), CurvePt({5.000, -5.000, -1.571}, 107.961, 0.000, NaN), CurvePt({5.000, -55.000, -1.571}, 157.961, 0.000, NaN)], 3.0, SpeedLimit(-Inf, Inf), LaneBoundary(:unknown, :unknown), LaneBoundary(:unknown, :unknown), LaneConnection{Int64, Float64}[], LaneConnection{Int64, Float64}[])])
 RoadSegment{Float64}(2, Lane{Float64}[Lane{Float64}(LaneTag(2, 1), CurvePt{Float64}[CurvePt({-100.000, 0.000, 0.000}, 0.000, 0.000, NaN), CurvePt({0.000, 0.000, 0.000}, 100.000, 0.000, NaN), CurvePt({13.000, 0.000, 0.000}, 113.000, 0.000, NaN), CurvePt({13.000, 0.000, 0.000}, 113.000, 0.000, NaN), CurvePt({63.000, 0.000, 0.000}, 163.000, 0.000, NaN)], 3.0, SpeedLimit(-Inf, Inf), LaneBoundary(:unknown, :unknown), LaneBoundary(:unknown, :unknown), LaneConnection{Int64, Float64}[], LaneConnection{Int64, Float64}[])])
 RoadSegment{Float64}(3, Lane{Float64}[Lane{Float64}(LaneTag(3, 1), CurvePt{Float64}[CurvePt({63.000, 3.000, 3.142}, 0.000, 0.000, NaN), CurvePt({13.000, 3.000, 3.142}, 50.000, 0.000, NaN), CurvePt({0.000, 3.000, 3.142}, 63.000, 0.000, NaN), CurvePt({0.000, 3.000, 3.142}, 63.000, 0.000, NaN), CurvePt({-100.000, 3.000, 3.142}, 163.000, 0.000, NaN)], 3.0, SpeedLimit(-Inf, Inf), LaneBoundary(:unknown, :unknown), LaneBoundary(:unknown, :unknown), LaneConnection{Int64, Float64}[], LaneConnection{Int64, Float64}[])])
 RoadSegment{Float64}(4, Lane{Float64}[Lane{Float64}(LaneTag(4, 1), CurvePt{Float64}[CurvePt({63.000, 3.000, 3.142}, 0.000, 0.000, NaN), CurvePt({13.000, 3.000, 3.142}, 50.000, 0.000, NaN), CurvePt({12.731, 2.996, -3.110}, 50.269, 0.117, NaN), CurvePt({12.465, 2.983, -3.079}, 50.535, 0.118, NaN), CurvePt({12.201, 2.963, -3.048}, 50.800, 0.119, NaN), CurvePt({11.940, 2.934, -3.016}, 51.062, 0.120, NaN), CurvePt({11.683, 2.898, -2.985}, 51.323, 0.121, NaN), CurvePt({11.428, 2.853, -2.954}, 51.582, 0.122, NaN), CurvePt({11.176, 2.801, -2.922}, 51.839, 0.123, NaN), CurvePt({10.927, 2.741, -2.890}, 52.094, 0.124, NaN)  …  CurvePt({5.199, -3.176, -1.790}, 60.764, 0.123, NaN), CurvePt({5.147, -3.428, -1.759}, 61.022, 0.122, NaN), CurvePt({5.103, -3.683, -1.727}, 61.280, 0.121, NaN), CurvePt({5.066, -3.940, -1.696}, 61.541, 0.120, NaN), CurvePt({5.037, -4.201, -1.665}, 61.803, 0.119, NaN), CurvePt({5.017, -4.465, -1.633}, 62.068, 0.118, NaN), CurvePt({5.004, -4.731, -1.602}, 62.334, 0.117, NaN), CurvePt({5.000, -5.000, -1.571}, 62.603, 0.115, NaN), CurvePt({5.000, -5.000, -1.571}, 62.603, 0.000, NaN), CurvePt({5.000, -55.000, -1.571}, 112.603, 0.000, NaN)], 3.0, SpeedLimit(-Inf, Inf), LaneBoundary(:unknown, :unknown), LaneBoundary(:unknown, :unknown), LaneConnection{Int64, Float64}[], LaneConnection{Int64, Float64}[])])

Append right turn coming from below

curve = gen_straight_curve(convert(VecE2, D+VecE2(0,-50)), convert(VecE2, D), 2)
append_to_curve!(curve, gen_bezier_curve(D, E, 0.6r, 0.6r, 51)[2:end])
append_to_curve!(curve, gen_straight_curve(convert(VecE2, E), convert(VecE2, E+VecE2(50,0)), 2))
lane = Lane(LaneTag(length(roadway.segments)+1,1), curve)
push!(roadway.segments, RoadSegment(lane.tag.segment, [lane]))
5-element Vector{RoadSegment{Float64}}:
 RoadSegment{Float64}(1, Lane{Float64}[Lane{Float64}(LaneTag(1, 1), CurvePt{Float64}[CurvePt({-100.000, 0.000, 0.000}, 0.000, 0.000, NaN), CurvePt({0.000, 0.000, 0.000}, 100.000, 0.000, NaN), CurvePt({0.179, -0.002, -0.027}, 100.179, -0.153, NaN), CurvePt({0.355, -0.010, -0.054}, 100.355, -0.157, NaN), CurvePt({0.529, -0.021, -0.082}, 100.530, -0.162, NaN), CurvePt({0.700, -0.038, -0.110}, 100.702, -0.166, NaN), CurvePt({0.869, -0.059, -0.139}, 100.872, -0.171, NaN), CurvePt({1.035, -0.085, -0.168}, 101.040, -0.175, NaN), CurvePt({1.198, -0.115, -0.198}, 101.206, -0.180, NaN), CurvePt({1.359, -0.150, -0.227}, 101.370, -0.184, NaN)  …  CurvePt({4.885, -3.802, -1.373}, 106.755, -0.180, NaN), CurvePt({4.915, -3.965, -1.403}, 106.921, -0.175, NaN), CurvePt({4.941, -4.131, -1.432}, 107.089, -0.171, NaN), CurvePt({4.962, -4.300, -1.461}, 107.259, -0.166, NaN), CurvePt({4.979, -4.471, -1.489}, 107.431, -0.162, NaN), CurvePt({4.990, -4.645, -1.517}, 107.605, -0.157, NaN), CurvePt({4.998, -4.821, -1.544}, 107.782, -0.153, NaN), CurvePt({5.000, -5.000, -1.571}, 107.961, -0.148, NaN), CurvePt({5.000, -5.000, -1.571}, 107.961, 0.000, NaN), CurvePt({5.000, -55.000, -1.571}, 157.961, 0.000, NaN)], 3.0, SpeedLimit(-Inf, Inf), LaneBoundary(:unknown, :unknown), LaneBoundary(:unknown, :unknown), LaneConnection{Int64, Float64}[], LaneConnection{Int64, Float64}[])])
 RoadSegment{Float64}(2, Lane{Float64}[Lane{Float64}(LaneTag(2, 1), CurvePt{Float64}[CurvePt({-100.000, 0.000, 0.000}, 0.000, 0.000, NaN), CurvePt({0.000, 0.000, 0.000}, 100.000, 0.000, NaN), CurvePt({13.000, 0.000, 0.000}, 113.000, 0.000, NaN), CurvePt({13.000, 0.000, 0.000}, 113.000, 0.000, NaN), CurvePt({63.000, 0.000, 0.000}, 163.000, 0.000, NaN)], 3.0, SpeedLimit(-Inf, Inf), LaneBoundary(:unknown, :unknown), LaneBoundary(:unknown, :unknown), LaneConnection{Int64, Float64}[], LaneConnection{Int64, Float64}[])])
 RoadSegment{Float64}(3, Lane{Float64}[Lane{Float64}(LaneTag(3, 1), CurvePt{Float64}[CurvePt({63.000, 3.000, 3.142}, 0.000, 0.000, NaN), CurvePt({13.000, 3.000, 3.142}, 50.000, 0.000, NaN), CurvePt({0.000, 3.000, 3.142}, 63.000, 0.000, NaN), CurvePt({0.000, 3.000, 3.142}, 63.000, 0.000, NaN), CurvePt({-100.000, 3.000, 3.142}, 163.000, 0.000, NaN)], 3.0, SpeedLimit(-Inf, Inf), LaneBoundary(:unknown, :unknown), LaneBoundary(:unknown, :unknown), LaneConnection{Int64, Float64}[], LaneConnection{Int64, Float64}[])])
 RoadSegment{Float64}(4, Lane{Float64}[Lane{Float64}(LaneTag(4, 1), CurvePt{Float64}[CurvePt({63.000, 3.000, 3.142}, 0.000, 0.000, NaN), CurvePt({13.000, 3.000, 3.142}, 50.000, 0.000, NaN), CurvePt({12.731, 2.996, -3.110}, 50.269, 0.117, NaN), CurvePt({12.465, 2.983, -3.079}, 50.535, 0.118, NaN), CurvePt({12.201, 2.963, -3.048}, 50.800, 0.119, NaN), CurvePt({11.940, 2.934, -3.016}, 51.062, 0.120, NaN), CurvePt({11.683, 2.898, -2.985}, 51.323, 0.121, NaN), CurvePt({11.428, 2.853, -2.954}, 51.582, 0.122, NaN), CurvePt({11.176, 2.801, -2.922}, 51.839, 0.123, NaN), CurvePt({10.927, 2.741, -2.890}, 52.094, 0.124, NaN)  …  CurvePt({5.199, -3.176, -1.790}, 60.764, 0.123, NaN), CurvePt({5.147, -3.428, -1.759}, 61.022, 0.122, NaN), CurvePt({5.103, -3.683, -1.727}, 61.280, 0.121, NaN), CurvePt({5.066, -3.940, -1.696}, 61.541, 0.120, NaN), CurvePt({5.037, -4.201, -1.665}, 61.803, 0.119, NaN), CurvePt({5.017, -4.465, -1.633}, 62.068, 0.118, NaN), CurvePt({5.004, -4.731, -1.602}, 62.334, 0.117, NaN), CurvePt({5.000, -5.000, -1.571}, 62.603, 0.115, NaN), CurvePt({5.000, -5.000, -1.571}, 62.603, 0.000, NaN), CurvePt({5.000, -55.000, -1.571}, 112.603, 0.000, NaN)], 3.0, SpeedLimit(-Inf, Inf), LaneBoundary(:unknown, :unknown), LaneBoundary(:unknown, :unknown), LaneConnection{Int64, Float64}[], LaneConnection{Int64, Float64}[])])
 RoadSegment{Float64}(5, Lane{Float64}[Lane{Float64}(LaneTag(5, 1), CurvePt{Float64}[CurvePt({8.000, -55.000, 1.571}, 0.000, 0.000, NaN), CurvePt({8.000, -5.000, 1.571}, 50.000, 0.000, NaN), CurvePt({8.002, -4.821, 1.544}, 50.179, -0.153, NaN), CurvePt({8.010, -4.645, 1.517}, 50.355, -0.157, NaN), CurvePt({8.021, -4.471, 1.489}, 50.530, -0.162, NaN), CurvePt({8.038, -4.300, 1.461}, 50.702, -0.166, NaN), CurvePt({8.059, -4.131, 1.432}, 50.872, -0.171, NaN), CurvePt({8.085, -3.965, 1.403}, 51.040, -0.175, NaN), CurvePt({8.115, -3.802, 1.373}, 51.206, -0.180, NaN), CurvePt({8.150, -3.641, 1.343}, 51.370, -0.184, NaN)  …  CurvePt({11.802, -0.115, 0.198}, 56.755, -0.180, NaN), CurvePt({11.965, -0.085, 0.168}, 56.921, -0.175, NaN), CurvePt({12.131, -0.059, 0.139}, 57.089, -0.171, NaN), CurvePt({12.300, -0.038, 0.110}, 57.259, -0.166, NaN), CurvePt({12.471, -0.021, 0.082}, 57.431, -0.162, NaN), CurvePt({12.645, -0.010, 0.054}, 57.605, -0.157, NaN), CurvePt({12.821, -0.002, 0.027}, 57.782, -0.153, NaN), CurvePt({13.000, 0.000, 0.000}, 57.961, -0.148, NaN), CurvePt({13.000, 0.000, 0.000}, 57.961, 0.000, NaN), CurvePt({63.000, 0.000, 0.000}, 107.961, 0.000, NaN)], 3.0, SpeedLimit(-Inf, Inf), LaneBoundary(:unknown, :unknown), LaneBoundary(:unknown, :unknown), LaneConnection{Int64, Float64}[], LaneConnection{Int64, Float64}[])])

Append left turn coming from below

curve = gen_straight_curve(convert(VecE2, D+VecE2(0,-50)), convert(VecE2, D), 2)
append_to_curve!(curve, gen_bezier_curve(D, A, 0.9r, 0.9r, 51)[2:end])
append_to_curve!(curve, gen_straight_curve(convert(VecE2, A), convert(VecE2, A+VecE2(-100,0)), 2))
lane = Lane(LaneTag(length(roadway.segments)+1,1), curve)
push!(roadway.segments, RoadSegment(lane.tag.segment, [lane]))

snapshot = render([roadway])

intersection

We can identify each lane thanks to the following user-defined functions. We define a LaneOverlay object that indicate the lane to highlight. One could implement any custom type to display other information on the lane. We then add a new method to the add_renderable! function that execute the specific action (coloring in blue). Look at AutomotiveVisualization.jl for more detail on the function add_renderable!.

The following animation iterates over the individual lanes of the intersection layout and highlights them:

struct LaneOverlay
    roadway::Roadway
    lane::Lane
    color::Colorant
end
function AutomotiveVisualization.add_renderable!(rendermodel::RenderModel, overlay::LaneOverlay)
    add_renderable!(rendermodel, overlay.lane, overlay.roadway, color_asphalt=overlay.color)
end


using Reel

animation = roll(fps=1.0, duration=length(roadway.segments)) do t, dt
    i = Int(floor(t/dt)) + 1
    renderables = [
        roadway,
        LaneOverlay(roadway, roadway[LaneTag(i,1)], RGBA(0.0,0.0,1.0,0.5))
    ]
    render(renderables)
end;

highlighted lanes

Let's populate the intersection

vs0 = VehicleState(B + polar(50.0,-π), roadway, 8.0) # initial state of the vehicle
scene = Scene([Entity(vs0, VehicleDef(), 1)])

snapshot = render([roadway, scene])

populated intersection

We will use lateral and longitudinal acceleration to control a car in the intersection. The first step is to define a corresponding action type that will contain the acceleration inputs.

struct LaneSpecificAccelLatLon
    a_lat::Float64
    a_lon::Float64
end

Next, add a method to the propagate function to update the state using our new action type.

function AutomotiveSimulator.propagate(veh::Entity, action::LaneSpecificAccelLatLon, roadway::Roadway, Δt::Float64)
    lane_tag_orig = veh.state.posF.roadind.tag
    state = propagate(veh, LatLonAccel(action.a_lat, action.a_lon), roadway, Δt)
    roadproj = proj(state.posG, roadway[lane_tag_orig], roadway, move_along_curves=false)
    retval = VehicleState(Frenet(roadproj, roadway), roadway, state.v)
    return retval
end

Driver Model:

We define a driver model, which can be seen as a distribution over actions. # TODO Here we will define the simplest model, which is to repeat the same action.

struct InterDriver <: DriverModel{LaneSpecificAccelLatLon}
    a::LaneSpecificAccelLatLon
end

AutomotiveSimulator.observe!(model::InterDriver, scene::Scene, roadway::Roadway, egoid::Int64) = model
Base.rand(::AbstractRNG, model::InterDriver) = model.a

Simulate:

First associate a model to each driver in the scene using a dictionary. Here we only have one driver identified by its ID: 1. Then everything is ready to run the simulate! function.

using Reel

timestep = 0.1
nticks = 100

vs0 = VehicleState(B + polar(50.0,-π), roadway, 8.0)
scene = Scene([Entity(vs0, VehicleDef(), 1)])
models = Dict(1 => InterDriver(LaneSpecificAccelLatLon(0.0,0.0)))
scenes = simulate(scene, roadway, models, nticks, timestep)

animation = roll(fps=1.0/timestep, duration=nticks*timestep) do t, dt
    i = Int(floor(t/dt)) + 1
    renderables = [roadway, scenes[i]]
    render(renderables)
end
"animated_intersection.gif"

animated intersection


This page was generated using Literate.jl.