Welcome to Scenic’s documentation!¶
Scenic is a domain-specific probabilistic programming language for modeling the environments of cyber-physical systems like robots and autonomous cars. A Scenic program defines a distribution over scenes, configurations of physical objects and agents; sampling from this distribution yields concrete scenes which can be simulated to produce training or testing data.
Scenic was designed and implemented by Daniel J. Fremont, Tommaso Dreossi, Shromona Ghosh, Xiangyu Yue, Alberto L. Sangiovanni-Vincentelli, and Sanjit A. Seshia. For a description of the language and some of its applications, see our PLDI 2019 paper; a more in-depth discussion is in Chapters 5 and 8 of this thesis. Our publications page lists additional papers using Scenic.
If you have any problems using Scenic, please submit an issue to our GitHub repository or contact Daniel at dfremont@ucsc.edu.
Table of Contents¶
Getting Started with Scenic¶
Installation¶
Scenic requires Python 3.6 or newer. You can install Scenic from PyPI by simply running:
pip install scenic
Alternatively, you can download or clone the Scenic repository, which contains examples we’ll use below. Install Poetry, activate the virtual environment in which you would like to run Scenic, and then run:
poetry install
If you will be developing Scenic, add the -E dev
option when invoking Poetry.
Note
If you are not already using a virtual environment, poetry install
will create one.
You can then run poetry shell
to create a terminal inside the environment for running
the commands below.
Either of the options above should install all of the dependencies which are required to run Scenic.
Scenarios using the scenic.simulators.webots.guideways
model also require the pyproj
package, and will prompt you if you don’t have it.
Note
For Windows, we recommend using bashonwindows (the Windows subsystem for Linux) on Windows 10. Instructions for installing poetry on bashonwindows can be found here.
In the past, the shapely
package did not install properly on Windows.
If you encounter this issue, try installing it manually following the instructions here.
Note
You may also want to install the Polygon3
package (pip install Polygon3
) to get
faster and more robust polygon triangulation. However, this package is based on the
GPC library, which is only free for non-commercial use.
Trying Some Examples¶
The Scenic repository contains many example scenarios, found in the examples
directory.
They are organized by the simulator they are written for, e.g. GTA or Webots.
Each simulator has a specialized Scenic interface which requires additional setup (see Supported Simulators); however, for convenience Scenic provides an easy way to visualize scenarios without running a simulator.
Simply run the scenic
module as a script, giving a path to a Scenic file:
python -m scenic examples/gta/badlyParkedCar2.scenic
This will compile the Scenic program and sample from it, displaying a schematic of the resulting scene. Since this is the badly-parked car example from our GTA case study, you should get something like this:

Here the circled rectangle is the ego car; its view cone extends to the right, where we see another car parked rather poorly at the side of the road (the white lines are curbs). If you close the window, Scenic will sample another scene from the same scenario and display it. This will repeat until you kill the generator (Control-c in Linux; right-clicking on the Dock icon and selecting Quit on OS X).
Scenarios for the other simulators can be viewed in the same way. Here are a few for Webots:
python -m scenic examples/webots/mars/narrowGoal.scenic
python -m scenic examples/webots/road/crossing.scenic
python -m scenic examples/webots/guideways/uberCrash.scenic



Learning More¶
Depending on what you’d like to do with Scenic, different parts of the documentation may be helpful:
If you want to learn how to write Scenic programs, see the tutorial.
If you want to use Scenic with a simulator, see the Supported Simulators page (which also describes how to interface Scenic to a new simulator, if the one you want isn’t listed).
If you want to add a feature to the language or otherwise need to understand Scenic’s inner workings, see our page on Scenic Internals.
Scenic Tutorial¶
This tutorial motivates and illustrates the main features of Scenic, focusing on aspects of the language that make it particularly well-suited for describing geometric scenarios. Throughout, we use examples from our case study using Scenic to generate traffic scenes in GTA V to test and train autonomous cars [F19].
Classes, Objects, and Geometry¶
To start, suppose we want scenes of one car viewed from another on the road. We can write this very concisely in Scenic:
1 2 3 | from scenic.simulators.gta.model import Car
ego = Car
Car
|
Line 1 imports the GTA world model, a Scenic library defining everything specific to our
GTA interface. This includes the definition of the class Car
, as well as information
about the road geometry that we’ll see later. We’ll suppress this import
statement in
subsequent examples.
Line 2 then creates a Car
and assigns it to the special variable ego
specifying the
ego object. This is the reference point for the scenario: our simulator interfaces
typically use it as the viewpoint for rendering images, and many of Scenic’s geometric
operators use ego
by default when a position is left implicit (we’ll see an example
momentarily).
Finally, line 3 creates a second Car
. Compiling this scenario with Scenic, sampling a
scene from it, and importing the scene into GTA V yields an image like this:

A scene sampled from the simple car scenario, rendered in GTA V.¶
Note that both the ego
car (where the camera is located) and the second car are both
located on the road and facing along it, despite the fact that the code above does not
specify the position or any other properties of the two cars. This is because in Scenic,
any unspecified properties take on the default values inherited from the object’s
class. Slightly simplified, the definition of the class Car
begins:
1 2 3 4 5 6 | class Car:
position: Point on road
heading: roadDirection at self.position
width: self.model.width
height: self.model.height
model: CarModel.defaultModel() # a distribution over several car models
|
Here road
is a region, one of Scenic’s primitive types, defined in the gta
model
to specify which points in the workspace are on a road. Similarly, roadDirection
is a
vector field specifying the nominal traffic direction at such points. The operator
F at X
simply gets the direction of the field F at point X, so line 3
sets a Car
’s default heading to be the road direction at its position
. The default
position
, in turn, is a Point on road
(we will explain this syntax shortly),
which means a uniformly random point on the road. Thus, in our simple scenario above both
cars will be placed on the road facing a reasonable direction, without our having to
specify this explicitly.
We can of course override the class-provided defaults and define the position of an object more specifically. For example,
1 | Car offset by (-10, 10) @ (20, 40)
|
creates a car that is 20–40 meters ahead of the camera (the ego
), and up to 10
meters to the left or right, while still using the default heading (namely, being aligned
with the road). Here the interval notation (X, Y)
creates a uniform
distribution on the interval, and X @ Y
creates a vector from xy
coordinates (as in Smalltalk [GR83]).
Local Coordinate Systems¶
Scenic provides a number of constructs for working with local coordinate systems, which
are often helpful when building a scene incrementally out of component parts. Above, we
saw how offset by
could be used to position an object in the coordinate system of the
ego
, for instance placing a car a certain distance away from the camera 1.
It is equally easy in Scenic to use local coordinate systems around other objects or even arbitrary points. For example, suppose we want to make the scenario above more realistic by not requiring the car to be exactly aligned with the road, but to be within say 5°. We could write
1 2 | Car offset by (-10, 10) @ (20, 40),
facing (-5, 5) deg
|
but this is not quite what we want, since this sets the orientation of the car in
global coordinates. Thus the car will end up facing within 5° of North, rather than
within 5° of the road direction. Instead, we can use Scenic’s general operator
X relative to Y
, which can interpret vectors and headings as being in a
variety of local coordinate systems:
If instead we want the heading to be relative to that of the ego car, so that the two
cars are (roughly) aligned, we can simply write (-5, 5) deg relative to ego
.
Notice that since roadDirection
is a vector field, it defines a different local
coordinate system at each point in space: at different points on the map, roads point
different directions! Thus an expression like 15 deg relative to field
does not
define a unique heading. The example above works because Scenic knows that the
expression (-5, 5) deg relative to roadDirection
depends on a reference position, and
automatically uses the position
of the Car
being defined. This is a feature of
Scenic’s system of specifiers, which we explain next.
Readable, Flexible Specifiers¶
The syntax offset by X
and facing Y
for specifying positions and
orientations may seem unusual compared to typical constructors in object-oriented
languages. There are two reasons why Scenic uses this kind of syntax: first, readability.
The second is more subtle and based on the fact that in natural language there are many
ways to specify positions and other properties, some of which interact with each other.
Consider the following ways one might describe the location of an object:
“is at position X” (an absolute position)
“is just left of position X” (a position based on orientation)
“is 3 m West of the taxi” (a relative position)
“is 3 m left of the taxi” (a local coordinate system)
“is one lane left of the taxi” (another local coordinate system)
“appears to be 10 m behind the taxi” (relative to the line of sight)
“is 10 m along the road from the taxi” (following a potentially-curving vector field)
These are all fundamentally different from each other: for example, (4) and (5) differ if the taxi is not parallel to the lane.
Furthermore, these specifications combine other properties of the object in different
ways: to place the object “just left of” a position, we must first know the object’s
heading
; whereas if we wanted to face the object “towards” a location, we must
instead know its position
. There can be chains of such dependencies: for example,
the description “the car is 0.5 m left of the curb” means that the right edge of the
car is 0.5 m away from the curb, not its center, which is what the car’s position
property stores. So the car’s position
depends on its width
, which in turn
depends on its model
. In a typical object-oriented language, these dependencies might
be handled by first computing values for position
and all other properties, then
passing them to a constructor. For “a car is 0.5 m left of the curb” we might write
something like:
# hypothetical Python-like language
model = Car.defaultModelDistribution.sample()
pos = curb.offsetLeft(0.5 + model.width / 2)
car = Car(pos, model=model)
Notice how model
must be used twice, because model
determines both the model of
the car and (indirectly) its position. This is inelegant, and breaks encapsulation
because the default model distribution is used outside of the Car
constructor. The
latter problem could be fixed by having a specialized constructor or factory function:
# hypothetical Python-like language
car = CarLeftOfBy(curb, 0.5)
However, such functions would proliferate since we would need to handle all possible combinations of ways to specify different properties (e.g. do we want to require a specific model? Are we overriding the width provided by the model for this specific car?). Instead of having a multitude of such monolithic constructors, Scenic factors the definition of objects into potentially-interacting but syntactically-indepdendent parts:
1 2 | Car left of spot by 0.5,
with model CarModel.models['BUS']
|
Here left of X by D
and with model M
are specifiers which do not
have an order, but which together specify the properties of the car. Scenic works out
the dependencies between properties (here, position
is provided by left of
, which
depends on width
, whose default value depends on model
) and evaluates them in the
correct order. To use the default model distribution we would simply omit line 2; keeping
it affects the position
of the car appropriately without having to specify BUS
more than once.
Specifying Multiple Properties Together¶
Recall that we defined the default position
for a Car
to be a Point on road
:
this is an example of another specifier, on region
, which specifies
position
to be a uniformly random point in the given region. This specifier
illustrates another feature of Scenic, namely that specifiers can specify multiple
properties simultaneously. Consider the following scenario, which creates a parked car
given a region curb
(also defined in the scenic.simulators.gta.model
library):
1 2 | spot = OrientedPoint on visible curb
Car left of spot by 0.25
|
The function visible region
returns the part of the region that is visible from
the ego object. The specifier on visible curb
with then set position
to be a
uniformly random visible point on the curb. We create spot
as an OrientedPoint
,
which is a built-in class that defines a local coordinate system by having both a
position
and a heading
. The on region
specifier can also specify
heading
if the region has a preferred orientation (a vector field) associated with
it: in our example, curb
is oriented by roadDirection
. So spot
is, in fact,
a uniformly random visible point on the curb, oriented along the road. That orientation
then causes the Car
to be placed 0.25 m left of spot
in spot
’s local coordinate
system, i.e. 0.25 m away from the curb, as desired.
In fact, Scenic makes it easy to elaborate this scenario without needing to alter the
code above. Most simply, we could specify a particular model or non-default distribution
over models by just adding with model M
to the definition of the Car
. More
interestingly, we could produce a scenario for badly-parked cars by adding two lines:
1 2 3 4 | spot = OrientedPoint on visible curb
badAngle = Uniform(1, -1) * (10, 20) deg
Car left of spot by 0.25,
facing badAngle relative to roadDirection
|
This will yield cars parked 10-20° off from the direction of the curb, as seen in the image below. This example illustrates how specifiers greatly enhance Scenic’s flexibility and modularity.

A scene sampled from the badly-parked car scenario, rendered in GTA V.¶
Declarative Hard and Soft Constraints¶
Notice that in the scenarios above we never explicitly ensured that two cars will not intersect each other. Despite this, Scenic will never generate such scenes. This is because Scenic enforces several default requirements:
All objects must be contained in the workspace, or a particular specified region. For example, we can define the
Car
class so that all of its instances must be contained in the regionroad
by default.Objects must not intersect each other (unless explicitly allowed).
Objects must be visible from the ego object (so that they affect the rendered image; this requirement can also be disabled, for example for dynamic scenarios).
Scenic also allows the user to define custom requirements checking arbitrary conditions built from various geometric predicates. For example, the following scenario produces a car headed roughly towards the camera, while still facing the nominal road direction:
1 2 3 | ego = Car on road
car2 = Car offset by (-10, 10) @ (20, 40), with viewAngle 30 deg
require car2 can see ego
|
Here we have used the X can see Y
predicate, which in this case is checking
that the ego car is inside the 30° view cone of the second car.
Requirements, called observations in other probabilistic programming languages, are
very convenient for defining scenarios because they make it easy to restrict attention to
particular cases of interest. Note how difficult it would be to write the scenario above
without the require
statement: when defining the ego car, we would have to somehow
specify those positions where it is possible to put a roughly-oncoming car 20–40 meters
ahead (for example, this is not possible on a one-way road). Instead, we can simply place
ego
uniformly over all roads and let Scenic work out how to condition the
distribution so that the requirement is satisfied 2. As this example illustrates,
the ability to declaratively impose constraints gives Scenic greater versatility than
purely-generative formalisms. Requirements also improve encapsulation by allowing us to
restrict an existing scenario without altering it. For example:
1 2 3 | import genericTaxiScenario # import another Scenic scenario
fifthAvenue = ... # extract a Region from a map here
require genericTaxiScenario.taxi on fifthAvenue
|
The constraints in our examples above are hard requirements which must always be satisfied. Scenic also allows imposing soft requirements that need only be true with some minimum probability:
1 | require[0.5] car2 can see ego # condition only needs to hold with prob. >= 0.5
|
Such requirements can be useful, for example, in ensuring adequate representation of a particular condition when generating a training set: for instance, we could require that at least 90% of generated images have a car driving on the right side of the road.
Mutations¶
A common testing paradigm is to randomly generate variations of existing tests. Scenic supports this paradigm by providing syntax for performing mutations in a compositional manner, adding variety to a scenario without changing its code. For example, given a complex scenario involving a taxi, we can add one additional line:
1 2 | from bigScenario import taxi
mutate taxi
|
The mutate
statement will add Gaussian noise to the position
and heading
properties of taxi
, while still enforcing all built-in and custom requirements. The
standard deviation of the noise can be scaled by writing, for example,
mutate taxi by 2
(which adds twice as much noise), and in fact can be controlled
separately for position
and heading
(see scenic.core.object_types.Mutator
).
A Worked Example¶
We conclude with a larger example of a Scenic program which also illustrates the language’s utility across domains and simulators. Specifically, we consider the problem of testing a motion planning algorithm for a Mars rover able to climb over rocks. Such robots can have very complex dynamics, with the feasibility of a motion plan depending on exact details of the robot’s hardware and the geometry of the terrain. We can use Scenic to write a scenario generating challenging cases for a planner to solve in simulation.
We will write a scenario representing a rubble field of rocks and piples with a
bottleneck between the rover and its goal that forces the path planner to consider
climbing over a rock. First, we import a small Scenic library for the Webots robotics
simulator (scenic.simulators.webots.mars.model
) which defines the (empty) workspace
and several types of objects: the Rover
itself, the Goal
(represented by a flag), and
debris classes Rock
, BigRock
, and Pipe
. Rock
and BigRock
have fixed sizes, and
the rover can climb over them; Pipe
cannot be climbed over, and can represent a pipe of
arbitrary length, controlled by the height
property (which corresponds to Scenic’s
y axis).
1 | from scenic.simulators.webots.mars.model import *
|
Then we create the rover at a fixed position and the goal at a random position on the other side of the workspace:
2 3 | ego = Rover at 0 @ -2
goal = Goal at (-2, 2) @ (2, 2.5)
|
Next we pick a position for the bottleneck, requiring it to lie roughly on the way from the robot to its goal, and place a rock there.
4 5 6 7 | bottleneck = OrientedPoint offset by (-1.5, 1.5) @ (0.5, 1.5),
facing (-30, 30) deg
require abs((angle to goal) - (angle to bottleneck)) <= 10 deg
BigRock at bottleneck
|
Note how we define bottleneck
as an OrientedPoint
, with a range of possible
orientations: this is to set up a local coordinate system for positioning the pipes
making up the bottleneck. Specifically, we position two pipes of varying lengths on
either side of the bottleneck, with their ends far enough apart for the robot to be able
to pass between:
8 9 10 11 12 13 14 | halfGapWidth = (1.2 * ego.width) / 2
leftEnd = OrientedPoint left of bottleneck by halfGapWidth,
facing (60, 120) deg relative to bottleneck
rightEnd = OrientedPoint right of bottleneck by halfGapWidth,
facing (-120, -60) deg relative to bottleneck
Pipe ahead of leftEnd, with height (1, 2)
Pipe ahead of rightEnd, with height (1, 2)
|
Finally, to make the scenario slightly more interesting, we add several additional obstacles, positioned either on the far side of the bottleneck or anywhere at random (recalling that Scenic automatically ensures that no objects will overlap).
15 16 17 18 19 20 | BigRock beyond bottleneck by (-0.5, 0.5) @ (0.5, 1)
BigRock beyond bottleneck by (-0.5, 0.5) @ (0.5, 1)
Pipe
Rock
Rock
Rock
|
This completes the scenario, which can also be found in the Scenic repository under
examples/webots/mars/narrowGoal.scenic
. Several scenes generated from the
scenario and visualized in Webots are shown below.

A scene sampled from the Mars rover scenario, rendered in Webots.¶



Further Reading¶
This tutorial illustrated the syntax of Scenic through several simple examples. Much more
complex scenarios are possible, such as the platoon and bumper-to-bumper traffic GTA V
scenarios shown below. For many further examples using a variety of simulators, see the
examples
folder, as well as the links in the Supported Simulators page.






For a comprehensive overview of Scenic’s syntax, including details on all specifiers, operators, distributions, statements, and built-in classes, see the Scenic Syntax Reference. Our Guide to Scenic Syntax summarizes all of these language constructs in convenient tables with links to the detailed documentation.
Footnotes
- 1
In fact,
ego
is a variable and can be reassigned, so we can setego
to one object, build a part of the scene around it, then reassignego
and build another part of the scene.- 2
On the other hand, Scenic may have to work hard to satisfy difficult constraints. Ultimately Scenic falls back on rejection sampling, which in the worst case will run forever if the constraints are inconsistent (although we impose a limit on the number of iterations: see
Scenario.generate
).
References
Guide to Scenic Syntax¶
This page summarizes the syntax of Scenic (excluding syntax inherited from Python). For more details, click the links for individual language constructs to go to the corresponding section of the Scenic Syntax Reference.
Primitive Data Types¶
Booleans |
expressing truth values |
representing distances, angles, etc. as floating-point numbers |
|
representing positions and offsets in space |
|
representing orientations in space |
|
associating an orientation (i.e. a heading) to each point in space |
|
representing sets of points in space |
Distributions¶
(low, high) |
uniformly distributed in the interval |
Normal(mean, stdDev) |
normal distribution with the given mean and standard deviation |
Uniform(value, …) |
uniform over a finite set of values |
Discrete({value: weight, … }) |
discrete with given values and weights |
Objects¶
Property |
Default |
Meaning |
position |
0 @ 0 |
position in global coordinates |
viewDistance |
50 |
distance for the ‘can see’ operator |
mutationScale |
0 |
overall scale of mutations |
positionStdDev |
1 |
mutation standard deviation for position |
heading |
0 |
heading in global coordinates |
viewAngle |
360 degrees |
angle for the ‘can see’ operator |
headingStdDev |
5 degrees |
mutation standard deviation for heading |
width |
1 |
width of bounding box (X axis) |
height |
1 |
height of bounding box (Y axis) |
regionContainedIn |
workspace |
Region the object must lie within |
allowCollisions |
false |
whether collisions are allowed |
requireVisible |
true |
whether object must be visible from ego |
Specifiers¶

Illustration of the beyond
, behind
, and offset by
specifiers.
Each OrientedPoint
(e.g. P
) is shown as a bold arrow.¶
Specifier for Position |
Meaning |
---|---|
at vector |
Positions the object at the given global coordinates |
offset by vector |
Positions the object at the given coordinates in the local coordinate system of ego (which must already be defined) |
Positions the object at the given coordinates, in a local coordinate system centered at ego and oriented along the given direction |
|
Positions the object further to the left/right by the given scalar distance |
|
As above, except placing the object ahead of or behind the given position |
|
Positions the object at coordinates given by the second vector, centered at the first vector and oriented along the line of sight from the ego |
|
visible [from (Point | OrientedPoint)] |
Positions the object uniformly at random in the visible region of the ego, or of the given Point/OrientedPoint if given |
Specifiers for position and optionally heading |
Meaning |
---|---|
Positions the object uniformly at random in the given Region |
|
Positions the object to the left/right of the given OrientedPoint, depending on the object’s width |
|
(ahead of | behind) (OrientedPoint | Object) [by scalar ] |
As above, except positioning the object ahead of or behind the given OrientedPoint, thereby depending on height |
Positions the object at a point obtained by following the given vector field for the given distance starting from ego |
Specifiers for heading |
Meaning |
---|---|
facing heading |
Orients the object along the given heading in global coordinates |
facing vectorField |
Orients the object along the given vector field at the object’s position |
facing (toward | away from) vector |
Orients the object toward/away from the given position (thereby depending on the object’s position) |
Orients the object so that it has the given heading with respect to the line of sight from ego (or from the position given by the optional from vector) |
Operators¶

Illustration of several operators.
Each OrientedPoint
(e.g. P
) is shown as a bold arrow.¶
Scalar Operators |
Meaning |
---|---|
relative heading of heading [from heading] |
The relative heading of the given heading with respect to ego (or the heading provided with the optional from heading) |
apparent heading of OrientedPoint [from vector ] |
The apparent heading of the OrientedPoint, with respect to the line of sight from ego (or the position provided with the optional from vector ) |
distance [from vector ] to vector |
The distance to the given position from ego (or the position provided with the optional from vector ) |
The heading to the given position from ego (or the position provided with the optional from vector) |
Boolean Operators |
Meaning |
---|---|
Whether or not a position or Objectis visible from a Point or OrientedPoint. V |
|
Whether a position or Object lies in the region |
Heading Operators |
Meaning |
---|---|
The given heading, interpreted as being in degrees |
|
vectorField at vector |
The heading specified by the vector field at the given position |
The first direction, interpreted as an offset relative to the second direction |
Vector Operators |
Meaning |
---|---|
The first vector, interpreted as an offset relative to the second vector (or vice versa) |
|
The second vector, interpreted in a local coordinate system centered at the first vector and oriented along the given direction |
Region Operators |
Meaning |
---|---|
visible region |
The part of the given region visible from ego |
region visible from (Point | OrientedPoint) |
The part of the given region visible from the given Point/OrientedPoint |
OrientedPoint Operators |
Meaning |
---|---|
The given vector, interpreted in the local coordinate system of the OrientedPoint |
|
OrientedPoint offset by vector |
Equivalent to vector relative to OrientedPoint above |
(front | back | left | right) of Object |
The midpoint of the corresponding edge of the bounding box of the Object, oriented along its heading |
(front | back) (left | right) of Object |
The corresponding corner of the Object’s bounding box, also oriented along its heading |
Statements¶
Syntax |
Meaning |
---|---|
Imports a Scenic or Python module |
|
Defines global parameters of the scenario |
|
Defines a hard requirement |
|
Enables mutation of the given list of objects |
Scenic Syntax Reference¶
Primitive Data Types¶
Scalars¶
representing distances, angles, etc. as floating-point numbers, which can be sampled from various distributions
Vectors¶
representing positions and offsets in space, constructed from coordinates with the syntax X @ Y (inspired by Smalltalk). By convention, coordinates are in meters, although the semantics of Scenic does not depend on this. More significantly, the vector syntax is specialized for 2-dimensional space. The 2D assumption dramatically simplifies much of Scenic’s syntax (particularly that dealing with orientations, as we will see below), while still being adequate for a variety of applications. However, it is important to note that the fundamental ideas of Scenic are not specific to 2D, and it would be easy to extend our implementation of the language to support 3D space.
Headings¶
representing orientations in space. Conveniently, in 2D these can be expressed using a single angle (rather than Euler angles or a quaternion). Scenic represents headings in radians, measured anticlockwise from North, so that a heading of 0 is due North and a heading of π/2 is due West. We use the convention that the heading of a local coordinate system is the heading of its y-axis, so that, for example, -2 @ 3 means 2 meters left and 3 ahead.
Vector Fields¶
associating an orientation (i.e. a heading) to each point in space. For example, a vector field could represent the shortest paths to a destination, or the nominal traffic direction on a road
Regions¶
representing sets of points in space. Scenic provides a variety of ways to define Regions: rectangles, circular sectors, line segments, polygons, occupancy grids, and explicit lists of points. Regions can have an associated vector field giving points in the region preferred orientations. For example, a Region representing a lane of traffic could have a preferred orientation aligned with the lane, so that we can easily talk about distances along the lane, even if it curves. Another possible use of preferred orientations is to give the surface of an object normal vectors, so that other objects placed on the surface face outward by default.
Position Specifiers¶
offset along direction by vector¶
Positions the object at the given coordinates, in a local coordinate system centered at ego and oriented along the given direction (which, if a vector field, is evaluated at ego to obtain a heading)
(left | right) of vector [by scalar]¶
Depends on heading and width. Without the optional by scalar, positions the object immediately to the left/right of the given position; i.e., so that the midpoint of the object’s right/left edge is at that position. If by scalar is used, the object is placed further to the left/right by the given distance.
(ahead of | behind) vector [by scalar]¶
As above, except placing the object ahead of or behind the given position (so that the midpoint of the object’s back/front edge is at that position); thereby depending on heading and height.
beyond vector by vector [from vector]¶
Positions the object at coordinates given by the second vector, in a local coordinate system centered at the first vector and oriented along the line of sight from the ego. For example, beyond taxi by 0 @ 3 means 3 meters directly behind the taxi as viewed by the camera.
(in | on) region¶
Positions the object uniformly at random in the given Region. If the Region has a preferred orientation (a vector field), also optionally specifies heading to be equal to that orientation at the object’s position.
(left | right) of (OrientedPoint | Object) [by scalar]¶
Positions the object to the left/right of the given OrientedPoint, depending on the object’s width. Also optionally specifies heading to be the same as that of the OrientedPoint. If the OrientedPoint is in fact an Object, the object being constructed is positioned to the left/right of its left/right edge.
following vectorField [from vector ] for scalar¶
Positions the object at a point obtained by following the given vector field for the given distance starting from ego (or the position optionally provided with from vector ). Optionally specifies heading to be the heading of the vector field at the resulting point. Uses a forward Euler approximation of the continuous vector field
Heading Specifiers¶
apparently facing heading [from vector]¶
Orients the object so that it has the given heading with respect to the line of sight from ego (or from the position given by the optional from vector). For example, apparently facing 90 deg orients the object so that the camera views its left side head-on
Scalar Operators¶
angle [from vector ] to vector¶
The heading to the given position from ego (or the position provided with the optional from vector ). For example, if angle to taxi is zero, then taxi is due North of ego
Boolean Operators¶
(Point | OrientedPoint) can see (vector | Object)¶
Whether or not a position or Objectis visible from a Point or OrientedPoint. Visible regions are defined as follows: a Point can see out to a certain distance, and an OrientedPoint restricts this to the circular sector along its heading with a certain angle. A position is then visible if it lies in the visible region, and an Object is visible if its bounding box intersects the visible region. Note that Scenic’s visibility model does not take into account occlusion, although this would be straightforward to add
(vector | Object) in region¶
Whether a position or Object lies in the region; for the latter, the Object’s bounding box must be contained in the region. This allows us to use the predicate in two ways
Heading Operators¶
scalar deg¶
The given heading, interpreted as being in degrees. For example 90 deg evaluates to π/2
direction relative to direction¶
The first direction, interpreted as an offset relative to the second direction. For example, -5 deg relative to 90 deg is simply 85 deg. If either direction is a vector field, then this operator yields an expression depending on the position property of the object being specified
Vector Operators¶
vector (relative to | offset by) vector¶
The first vector, interpreted as an offset relative to the second vector (or vice versa). For example, 5@5 relative to 100@200 is 105@205. Note that this polymorphic operator has a specialized version for instances of OrientedPoint, defined below (so for example -3@0 relative to taxi will not use this vector version, even though the Object taxi can be coerced to a vector)
vector offset along direction by vector¶
The second vector, interpreted in a local coordinate system centered at the first vector and oriented along the given direction (which, if a vector field, is evaluated at the first vector to obtain a heading)
vector relative to OrientedPoint¶
The given vector, interpreted in the local coordinate system of the OrientedPoint. So for example 1 @ 2 relative to ego is 1 meter to the right and 2 meters ahead of ego
Statements¶
import module¶
Imports a Scenic or Python module. This statement behaves as in Python, but when importing a Scenic module M it also imports any objects created and requirements imposed in M. Scenic also supports the form from module import identifier, … , which as in Python imports the module plus one or more identifiers from its namespace
param identifier = value, …¶
Defines global parameters of the scenario. These have no semantics in Scenic, simply having their values included as part of the generated scene, but provide a general-purpose way to encode arbitrary global information
require boolean¶
Defines a hard requirement, requiring that the given condition hold in all instantiations of the scenario. As noted above, this is equivalent to an observe statement in other probabilistic programming languages
mutate identifier, … [by number ]¶
Enables mutation of the given list of objects, adding Gaussian noise with the given standard deviation (default 1) to their position and heading properties. If no objects are specified, mutation applies to every Object already created
Supported Simulators¶
Scenic is designed to be easily interfaced to any simulator (see Interfacing to New Simulators). On this page we list interfaces that we and others have developed; if you have a new interface, let us know and we’ll list it here!
Supported Simulators:
CARLA¶
Our interface to the CARLA simulator enables using Scenic to describe autonomous driving scenarios. This interface is part of the VerifAI toolkit; documentation and examples can be found in the VerifAI repository (the Scenic repository also has several other example scenarios).
Grand Theft Auto V¶
The interface to Grand Theft Auto V, used in our PLDI paper, allows Scenic to position cars within the game as well as to control the time of day and weather conditions.
Many examples using the interface (including all scenarios from the paper) can be found in examples/gta
.
See the paper and scenic.simulators.gta
for documentation.
Importing scenes into GTA V and capturing rendered images requires a GTA V plugin, which you can find here.
LGSVL (coming soon)¶
We have developed an interface to the LGSVL Simulator for autonomous driving, used in our ITSC 2020 paper. This interface will be released shortly.
Webots¶
We have several interfaces to the Webots robotics simulator, for different use cases.
An interface for the Mars rover example used in our PLDI paper. This interface is extremely simple and might be a good baseline for developing your own interface. See the examples in
examples/webots/mars
and the documentation ofscenic.simulators.webots.mars
for details.A general interface for traffic scenarios, used in our VerifAI paper. Examples using this interface can be found in the VerifAI repository; see also the documentation of
scenic.simulators.webots.road
.A more specific interface for traffic scenarios at intersections, using guideways from the Intelligent Intersections Toolkit. See the examples in
examples/webots/guideways
and the documentation ofscenic.simulators.webots.guideways
for details.
Note
Our interfaces were written for the R2018 version of Webots, which is not free but has lower hardware requirements than R2019. Relatively minor changes would be required to make our interfaces work with the newer open source versions of Webots. We may get around to porting them eventually; we’d also gladly accept a pull request!
X-Plane¶
Our interface to the X-Plane flight simulator enables using Scenic to describe aircraft taxiing scenarios. This interface is part of the VerifAI toolkit; documentation and examples can be found in the VerifAI repository.
Interfacing to New Simulators¶
To interface Scenic to a new simulator, there are two steps: using the Scenic API to compile scenarios and generate scenes, and writing a Scenic library defining the virtual world provided by the simulator.
Using the Scenic API¶
Compiling a Scenic scenario is easy: just call the scenic.scenarioFromFile
function with the path to a Scenic file (there’s also a variant scenic.scenarioFromString
which works on strings).
This returns a Scenario
object representing the scenario; to sample a scene from it, call its generate
method.
Scenes are represented by Scene
objects, from which you can extract the objects and their properties as well as the values of the global parameters (see the Scene
documentation for details).
Defining a World Model¶
To make writing scenarios for your simulator easier, you should write a Scenic library specifying all the relevant information about the simulated world. This “world model” could include:
Scenic classes (subclasses of
Object
) corresponding to types of objects in the simulator;instances of
Region
corresponding to locations of interest (e.g. one for each road);a
Workspace
specifying legal locations for objects (and optionally providing methods for schematically rendering scenes);any other information that might be useful in scenarios.
Then any Scenic programs for your simulator can import this world model and make use of the information within.
Each of the simulators natively supported by Scenic has a corresponding model.sc
file containing its world model.
See the Supported Simulators page for links to the module under scenic.simulators
for each simulator, where the world model can be found.
The scenic.simulators.webots.mars
model is particularly simple and would be a good place to start.
Scenic Internals¶
This section of the documentation describes the implementation of Scenic. It is not intended for ordinary users of Scenic, and will probably only be useful for people who need to make some change to the language (e.g. adding a new type of distribution).
The documentation is organized by the submodules of the main scenic
module:
Scenic’s core types and associated support code. |
|
World models and associated code for particular simulators. |
|
The Scenic compiler and associated support code. |
The scenic
module itself provides two functions as the top-level interface to Scenic:
-
scenarioFromFile
(path, cacheImports=False)[source]¶ Compile a Scenic file into a
Scenario
.- Parameters
path (str) – path to a Scenic file
cacheImports (bool) – Whether to cache any imported Scenic modules. The default behavior is to not do this, so that subsequent attempts to import such modules will cause them to be recompiled. If it is safe to cache Scenic modules across multiple compilations, set this argument to True. Then importing a Scenic module will have the same behavior as importing a Python module.
- Returns
A
Scenario
object representing the Scenic scenario.
Publications Using Scenic¶
Main Papers¶
The main paper on Scenic is:
Scenic: A Language for Scenario Specification and Scene Generation.Fremont, Dreossi, Ghosh, Yue, Sangiovanni-Vincentelli, and Seshia.PLDI 2019. [full version]
An expanded version of this paper appears as Chapters 5 and 8 of this thesis:
Algorithmic Improvisation. [thesis]Daniel J. Fremont.Ph.D. dissertation, 2019 (University of California, Berkeley; Group in Logic and the Methodology of Science).
Scenic is also integrated into the VerifAI toolkit, which is described in another paper:
VerifAI: A Toolkit for the Formal Design and Analysis of Artificial Intelligence-Based Systems.Dreossi*, Fremont*, Ghosh*, Kim, Ravanbakhsh, Vazquez-Chanlatte, and Seshia.
* Equal contribution.
Case Studies¶
We have also used Scenic in several industrial case studies:
Formal Analysis and Redesign of a Neural Network-Based Aircraft Taxiing System with VerifAI.Fremont, Chiu, Margineantu, Osipychev, and Seshia.Formal Scenario-Based Testing of Autonomous Vehicles: From Simulation to the Real World.Fremont, Kim, Pant, Seshia, Acharya, Bruso, Wells, Lemke, Lu, and Mehta.[See also this white paper and associated blog post]
Credits¶
If you use Scenic, we request that you cite our PLDI 2019 paper.
Scenic is primarily maintained by Daniel J. Fremont.
The Scenic project was started at UC Berkeley in Sanjit Seshia’s research group.
The language was developed by Daniel J. Fremont, Tommaso Dreossi, Shromona Ghosh, Xiangyu Yue, Alberto L. Sangiovanni-Vincentelli, and Sanjit A. Seshia.
Edward Kim assisted in putting together this documentation.
The Scenic tool has benefitted from code contributions from:
Johnathan Chiu
Francis Indaheng
Martin Jansa (LG Electronics, Inc.)
Wilson Wu
Finally, many other people provided helpful advice and discussions, including:
Ankush Desai
Alastair Donaldson
Andrew Gordon
Jonathan Ragan-Kelley
Sriram Rajamani
Marcell Vazquez-Chanlatte
Indices and Tables¶
License¶
Scenic is distributed under the 3-Clause BSD License.