Sidewalk

In this notebook, we will be creating a sidewalk environment in which pedestrians can walk along the sidewalk and cross the street as cars pass.


In [1]:
using Parameters
using AutomotiveDrivingModels
using AutoViz
using Interact


┌ Info: Recompiling stale cache file C:\Users\Maxime\.julia\compiled\v1.1\AutomotiveDrivingModels\ZEfHM.ji for AutomotiveDrivingModels [99497e54-f3d6-53d3-a3a9-fa9315a7f1ba]
└ @ Base loading.jl:1184
┌ Info: Precompiling AutoViz [82aa6e0c-a491-5edf-8d4b-c16b98e4ea17]
└ @ Base loading.jl:1186
┌ Info: Precompiling Interact [c601a237-2ae4-5e1e-952c-7a85b0c7eef1]
└ @ Base loading.jl:1186
┌ Warning: Module WebIO with build ID 614787941992320 is missing from the cache.
│ This may mean WebIO [0f1e0344-ec1d-5b48-a673-e5cf874b6c29] does not support precompilation but is imported by a module that does.
└ @ Base loading.jl:947
┌ Warning: Module WebIO with build ID 614787941992320 is missing from the cache.
│ This may mean WebIO [0f1e0344-ec1d-5b48-a673-e5cf874b6c29] does not support precompilation but is imported by a module that does.
└ @ Base loading.jl:947
┌ Warning: Module WebIO with build ID 614787941992320 is missing from the cache.
│ This may mean WebIO [0f1e0344-ec1d-5b48-a673-e5cf874b6c29] does not support precompilation but is imported by a module that does.
└ @ Base loading.jl:947
┌ Warning: The call to compilecache failed to create a usable precompiled cache file for InteractBase [d3863d7c-f0c8-5437-a7b4-3ae773c01009]
│   exception = Required dependency WebIO [0f1e0344-ec1d-5b48-a673-e5cf874b6c29] failed to load from a cache file.
└ @ Base loading.jl:969
┌ Warning: The call to compilecache failed to create a usable precompiled cache file for Interact [c601a237-2ae4-5e1e-952c-7a85b0c7eef1]
│   exception = ErrorException("Required dependency Knockout [bcebb21b-c2e3-54f8-a781-646b90f6d2cc] failed to load from a cache file.")
└ @ Base loading.jl:969
┌ Info: Recompiling stale cache file C:\Users\Maxime\.julia\compiled\v1.1\InteractBase\63c8J.ji for InteractBase [d3863d7c-f0c8-5437-a7b4-3ae773c01009]
└ @ Base loading.jl:1184

In [2]:
# Define sidewalk IDs
const TOP = 1
const BOTTOM = 2


Out[2]:
2

Creating the Environment

Here, we create a new type of environment called SidewalkEnv. It consists of a roadway, crosswalk, and sidewalk. A sidewalk is a Vector of Lanes that run alongside the road.


In [3]:
@with_kw mutable struct SidewalkEnv
    roadway::Roadway
    crosswalk::Lane
    sidewalk::Vector{Lane}
end


Out[3]:
SidewalkEnv

Defining the Sidewalk

We define the sidewalk's parameters.


In [4]:
# Geometry parameters
roadway_length = 100.
crosswalk_length = 15.
crosswalk_width = 6.0
crosswalk_pos = roadway_length/2
sidewalk_width = 3.0
sidewalk_pos = crosswalk_length/2 - sidewalk_width / 2


Out[4]:
6.0

Now we create the sidewalk environment. Our environment will consist of:

  • 1-way road with 2 lanes
  • Unsignalized zebra crosswalk perpendicular to the road
  • Sidewalks above and below the road

In [5]:
# Generate straight roadway of length roadway_length with 2 lanes.
# Returns a Roadway type (Array of segments).
# There is already a method to generate a simple straight roadway, which we use here.
roadway = gen_straight_roadway(2, roadway_length) 

# Generate the crosswalk.
# Our crosswalk does not have a predefined method for generation, so we define it with a LaneTag and a curve.
n_samples = 2 # for curve generation
crosswalk = Lane(LaneTag(2,1), gen_straight_curve(VecE2(crosswalk_pos, -crosswalk_length/2),
                                                  VecE2(crosswalk_pos, crosswalk_length/2),
                                                   n_samples), width = crosswalk_width)
cw_segment = RoadSegment(2, [crosswalk])
push!(roadway.segments, cw_segment) # Append the crosswalk to the roadway

# Generate the sidewalk.
top_sidewalk = Lane(LaneTag(3, TOP), gen_straight_curve(VecE2(0., sidewalk_pos),
                                                      VecE2(roadway_length, sidewalk_pos),
                                                        n_samples), width = sidewalk_width)
bottom_sidewalk = Lane(LaneTag(3, BOTTOM), gen_straight_curve(VecE2(0., -(sidewalk_pos - sidewalk_width)),
                                                          VecE2(roadway_length, -(sidewalk_pos - sidewalk_width)),
                                                            n_samples), width = sidewalk_width) 
    # Note: we subtract the sidewalk_width from the sidewalk position so that the edge is flush with the road.


sw_segment = RoadSegment(3, [top_sidewalk, bottom_sidewalk])
push!(roadway.segments, sw_segment)

# Initialize crosswalk environment
env = SidewalkEnv(roadway, crosswalk, [top_sidewalk, bottom_sidewalk]);

Since there is no defined render! method for the crosswalk and the sidewalk, we must define it ourselves.


In [6]:
function AutoViz.render!(rendermodel::RenderModel, env::SidewalkEnv)
    # Render sidewalk
    for sw in env.sidewalk
        curve = sw.curve
        n = length(curve)
        pts = Array{Float64}(undef, 2, n)
        for (i,pt) in enumerate(curve)
            pts[1,i] = pt.pos.x
            pts[2,i] = pt.pos.y
        end
        add_instruction!(rendermodel, render_line, (pts, colorant"grey", sw.width, Cairo.CAIRO_LINE_CAP_BUTT))
    end
    
    # Render roadway
    roadway = gen_straight_roadway(2, roadway_length)
    render!(rendermodel, roadway)
    
    # Render crosswalk
    curve = env.crosswalk.curve
    n = length(curve)
    pts = Array{Float64}(undef, 2, n)
    for (i,pt) in enumerate(curve)
        pts[1,i] = pt.pos.x
        pts[2,i] = pt.pos.y
    end

    # We can add render instructions from AutoViz.
    # Here we want the crosswalk to appear as a white-striped zebra crossing rather than a road.
    add_instruction!(rendermodel, render_dashed_line, (pts, colorant"white", env.crosswalk.width, 1.0, 1.0, 0.0, Cairo.CAIRO_LINE_CAP_BUTT))

    return rendermodel
end

In [ ]:
cam = FitToContentCamera(0.0)
render(Scene(), env, cam = cam);

Now we can define our pedestrian.


In [ ]:
# We define its class and the dimensions of its bounding box.
const PEDESTRIAN_DEF = VehicleDef(AgentClass.PEDESTRIAN, 1.0, 1.0)

We assign models to each agent in the scene.


In [ ]:
timestep = 0.1

# Crossing pedestrian definition
ped_init_state = VehicleState(VecSE2(49.0,-3.0,0.), env.sidewalk[BOTTOM], roadway, 1.3)
ped = Vehicle(ped_init_state, PEDESTRIAN_DEF, 1)

# Car definition
car_initial_state = VehicleState(VecSE2(0.0, 0., 0.), roadway.segments[1].lanes[1],roadway, 8.0)
car = Vehicle(car_initial_state, VehicleDef(), 2)

scene = Scene()
push!(scene, ped)
push!(scene, car)

# Define a model for each entity present in the scene
models = Dict{Int, DriverModel}()

ped_id = 1
car_id = 2

models[ped_id] = SidewalkPedestrianModel(timestep=timestep, 
                                            crosswalk=env.crosswalk,
                                            sw_origin = env.sidewalk[BOTTOM],
                                            sw_dest = env.sidewalk[TOP]
                                            )

models[car_id] = 
LatLonSeparableDriver( # produces LatLonAccels
        ProportionalLaneTracker(), # lateral model
        IntelligentDriverModel(), # longitudinal model
)

Simulate

Finally, we simulate the scene.


In [ ]:
nticks = 300
rec = SceneRecord(nticks+1, timestep)
# Execute the simulation
simulate!(rec, scene, roadway, models, nticks)
render(rec[0], env, cam=cam)

We can use a slider to scroll through each frame in the simulation. This usually takes less time than rendering a video.


In [ ]:
using Interact
@manipulate for frame_index in 1 : nframes(rec)
    render(rec[frame_index-nframes(rec)], env, cam=cam)
end

In [ ]: