Driving in a Stadium

This example demonstrates a 2D driving simulation where cars drive around a three-lane stadium. The entities are defined by the types:

  • S - VehicleState, containing the vehicle position (both globally and relative to the lane) and speed
  • D - VehicleDef, containing length, width, and class
  • I - Symbol, a unique label for each vehicle

The environment is represented by a Roadway object which allows to define roads consisting of multiple lanes based on the RNDF format.

We load relevant modules and generate a 3-lane stadium roadway:

using AutomotiveDrivingModels
using AutoViz
using Distributions

roadway = gen_stadium_roadway(3)
snapshot = render([roadway])

three lane stadium

As a next step, let's populate a scene with vehicles

w = DEFAULT_LANE_WIDTH
scene = Frame([
    Entity(VehicleState(VecSE2(10.0,  -w, 0.0), roadway, 29.0), VehicleDef(), :alice),
    Entity(VehicleState(VecSE2(40.0, 0.0, 0.0), roadway, 22.0), VehicleDef(), :bob),
    Entity(VehicleState(VecSE2(30.0, -2w, 0.0), roadway, 27.0), VehicleDef(), :charlie),
])
car_colors = get_pastel_car_colors(scene)
renderables = [
    roadway,
    (FancyCar(car=veh, color=car_colors[veh.id]) for veh in scene)...
]
snapshot = render(renderables)

stadium with cars

We can assign driver models to each agent and simulate the scenario.

timestep = 0.1
nticks = 300

models = Dict{Symbol, DriverModel}(
    :alice => LatLonSeparableDriver( # produces LatLonAccels
        ProportionalLaneTracker(), # lateral model
        IntelligentDriverModel(), # longitudinal model
    ),
    # :bob => Tim2DDriver(
    #     timestep, mlane = MOBIL(timestep),
    # ),
    :bob => StaticDriver{AccelTurnrate, MvNormal}(
        MvNormal([0.0,0.0], [1.0,0.1])
    ),
    :charlie => StaticDriver{AccelTurnrate, MvNormal}(
        MvNormal([0.0,0.0], [1.0,0.1])
    )
)

set_desired_speed!(models[:alice],   12.0)
set_desired_speed!(models[:bob],     10.0)
set_desired_speed!(models[:charlie],  8.0)

scenes = simulate(scene, roadway, models, nticks, timestep)

An animation of the simulation can be rendered using the Reel package

using Reel
using Printf

camera = TargetFollowCamera(:alice; zoom=10.)

animation = roll(fps=1.0/timestep, duration=nticks*timestep) do t, dt
    i = Int(floor(t/dt)) + 1
    update_camera!(camera, scenes[i])
    renderables = [
        roadway,
        (FancyCar(car=veh, color=car_colors[veh.id]) for veh in scenes[i])...,
        RenderableOverlay(IDOverlay(x_off=-2, y_off=1), scenes[i], roadway),
        TextOverlay(text=[@sprintf("time: %.1fs", t)], pos=VecE2(40,40), font_size=24)
    ]
    render(renderables, camera=camera)
end
"animated_stadium.gif"

animated stadium with cars

Alternatively, one can also use the Interact framework to inspect the simulation record interactively.

using Interact
using Reel
using Blink

w = Window()
viz = @manipulate for step in 1 : length(scenes)
    render([roadway, scenes[step]])
end
body!(w, viz)

The simulation results can be saved to a text file. We achieve this by first converting the list of scene to a Trajdata type and then exporting it.

TODO: fix writing of Trajdata

open("2Dstadium_listrec.txt", "w") do io
    @warn "TODO: need to fix bug in write(trajdata)"
    # write(io, MIME"text/plain"(), Trajdata(scenes, timestep))
end
┌ Warning: TODO: need to fix bug in write(trajdata)
└ @ Main.ex-driving_in_circles none:2

The trajectory data file can be loaded in a similar way.

# listrec = open("2Dstadium_listrec.txt", "r") do io
#     @warn "TODO: need to fix bug in write(trajdata)"
#     read(io, MIME"text/plain"(), Trajdata)
# end

# p = plot(listrec)
# TODO: maybe do something useful with the loaded data, like plot the speed over time or something