Skip to content

Sensors #195

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions examples/sensors/carla/data_generation/data_generation.scenic
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
param map = localPath('../../../../assets/maps/CARLA/Town05.xodr')
param carla_map = 'Town05'
model scenic.simulators.carla.model

# Sample a lane at random
lane = Uniform(*network.lanes)

spot = new OrientedPoint on lane.centerline

attrs = {"image_size_x": 1056,
"image_size_y": 704}

car_model = "vehicle.tesla.model3"

# Spawn car on that spot with logging autopilot behavior and
# - an RGB Camera pointing forward with specific attributes
# - a semantic segmentation sensor
ego = new Car at spot,
with blueprint car_model,
with behavior AutopilotBehavior(),
with sensors {"front_ss": SSSensor(offset=(1.6, 0, 1.7), convert='CityScapesPalette', attributes=attrs),
"front_rgb": RGBSensor(offset=(1.6, 0, 1.7), attributes=attrs)
}


other = new Car offset by 0 @ Range(10, 30),
with behavior AutopilotBehavior()

param recordFolder = "out/{simulation}"
record ego.observations["front_ss"] every 0.5 seconds after 5 seconds to "frontss_{time}.jpg"
record ego.observations["front_rgb"] after 5 seconds to "frontrgb.mp4"

terminate after 15 seconds
7 changes: 5 additions & 2 deletions src/scenic/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ def generateScene(maxIterations=2000):
return scene, iterations


def runSimulation(scene):
def runSimulation(scene, sceneCount):
startTime = time.time()
if args.verbosity >= 1:
print(f" Beginning simulation of {scene.dynamicScenario}...")
Expand All @@ -232,6 +232,7 @@ def runSimulation(scene):
lambda: simulator.simulate(
scene,
maxSteps=args.time,
name=str(sceneCount),
verbosity=args.verbosity,
maxIterations=args.max_sims_per_scene,
)
Expand Down Expand Up @@ -267,11 +268,13 @@ def runSimulation(scene):
"(try installing python3-tk)"
)

sceneCount = 0
successCount = 0
while True:
scene, _ = generateScene()
sceneCount += 1
if args.simulate:
success = runSimulation(scene)
success = runSimulation(scene, sceneCount)
if success:
successCount += 1
else:
Expand Down
44 changes: 34 additions & 10 deletions src/scenic/core/dynamics/scenarios.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import dataclasses
import functools
import inspect
import types
import weakref

import rv_ltl
Expand Down Expand Up @@ -183,8 +184,9 @@ def _start(self):
# Compute time limit now that we know the simulation timestep
self._elapsedTime = 0
self._timeLimitInSteps = self._timeLimit
timestep = veneer.currentSimulation.timestep
if self._timeLimitIsInSeconds:
self._timeLimitInSteps /= veneer.currentSimulation.timestep
self._timeLimitInSteps /= timestep

# create monitors for each requirement used for this simulation
self._requirementMonitors = [r.toMonitor() for r in self._temporalRequirements]
Expand All @@ -210,6 +212,13 @@ def _start(self):
for monitor in self._monitors:
monitor._start()

# Prepare recorders
simName = veneer.currentSimulation.name
globalParams = types.MappingProxyType(veneer._globalParameters)
for req in self._recordedExprs:
if (recConfig := req.recConfig) and (recorder := recConfig.recorder):
recorder.beginRecording(recConfig, simName, timestep, globalParams)

def _step(self):
"""Execute the (already-started) scenario for one time step.

Expand Down Expand Up @@ -301,13 +310,25 @@ def _stop(self, reason, quiet=False):
veneer.endScenario(self, reason, quiet=quiet)
super()._stop(reason)

# Reject if a temporal requirement was not satisfied.
# Check if a temporal requirement was not satisfied.
rejection = None
if not quiet:
for req in self._requirementMonitors:
if req.lastValue.is_falsy:
raise RejectSimulationException(str(req))
rejection = str(req)
break
self._requirementMonitors = None

# Stop recorders.
cancelRecordings = quiet or rejection is not None
for req in self._recordedExprs:
if (recConfig := req.recConfig) and (recorder := recConfig.recorder):
recorder.endRecording(canceled=cancelRecordings)

# If a temporal requirement was violated, reject (now that we're cleaned up).
if rejection is not None:
raise RejectSimulationException(rejection)

return reason

def _invokeInner(self, agent, subs):
Expand All @@ -333,7 +354,7 @@ def _invokeInner(self, agent, subs):
# Check if any sub-scenarios stopped during action execution
self._subScenarios = [sub for sub in self._subScenarios if sub._isRunning]

def _evaluateRecordedExprs(self, ty):
def _evaluateRecordedExprs(self, ty, step):
if ty is RequirementType.record:
place = "_recordedExprs"
elif ty is RequirementType.recordInitial:
Expand All @@ -342,14 +363,17 @@ def _evaluateRecordedExprs(self, ty):
place = "_recordedFinalExprs"
else:
assert False, "invalid record type requested"
return self._evaluateRecordedExprsAt(place)
return self._evaluateRecordedExprsAt(place, step)

def _evaluateRecordedExprsAt(self, place):
def _evaluateRecordedExprsAt(self, place, step):
values = {}
for rec in getattr(self, place):
values[rec.name] = rec.evaluate()
value = rec.evaluate()
values[rec.name] = value
if recorder := rec.recConfig.recorder:
recorder._record(value, step)
for sub in self._subScenarios:
subvals = sub._evaluateRecordedExprsAt(place)
subvals = sub._evaluateRecordedExprsAt(place, step)
values.update(subvals)
return values

Expand Down Expand Up @@ -407,9 +431,9 @@ def _registerObject(self, obj):

obj._parentScenario = weakref.ref(self)

def _addRequirement(self, ty, reqID, req, line, name, prob):
def _addRequirement(self, ty, reqID, req, line, name, prob, recConfig=None):
"""Save a requirement defined at compile-time for later processing."""
preq = PendingRequirement(ty, req, line, prob, name, self._ego)
preq = PendingRequirement(ty, req, line, prob, name, self._ego, recConfig)
self._pendingRequirements.append((reqID, preq))

def _addDynamicRequirement(self, ty, req, line, name):
Expand Down
6 changes: 6 additions & 0 deletions src/scenic/core/object_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -1052,6 +1052,9 @@ class Object(OrientedPoint):
value ``None``.
lastActions: Tuple of :term:`actions` taken by this agent in the last time step
(an empty tuple if the object is not an agent or this is the first time step).
sensors: Dict of ("name": sensor) that populate the observations field every time step
observations: Dict of ("name": observation) storing the latest observation of the sensor
with the same name
"""

_scenic_properties = {
Expand Down Expand Up @@ -1080,6 +1083,9 @@ class Object(OrientedPoint):
"lastActions": tuple(),
# weakref to scenario which created this object, for internal use
"_parentScenario": None,
# Sensor properties
"sensors": PropertyDefault((), {}, lambda self: {}),
"observations": PropertyDefault((), {"final"}, lambda self: {}),
}

def __new__(cls, *args, **kwargs):
Expand Down
5 changes: 4 additions & 1 deletion src/scenic/core/requirements.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,13 @@ def constrainsSampling(self):


class PendingRequirement:
def __init__(self, ty, condition, line, prob, name, ego):
def __init__(self, ty, condition, line, prob, name, ego, recConfig):
self.ty = ty
self.condition = condition
self.line = line
self.prob = prob
self.name = name
self.recConfig = recConfig

# the translator wrapped the requirement in a lambda to prevent evaluation,
# so we need to save the current values of all referenced names; we save
Expand Down Expand Up @@ -187,6 +188,7 @@ def __init__(self, compiledReq, sample, proposition):
self.closure = compiledReq.closure
self.line = compiledReq.line
self.name = compiledReq.name
self.recConfig = compiledReq.recConfig
self.sample = sample
self.compiledReq = compiledReq
self.proposition = proposition
Expand Down Expand Up @@ -440,6 +442,7 @@ def __init__(self, pendingReq, closure, dependencies, proposition):
self.line = pendingReq.line
self.name = pendingReq.name
self.prob = pendingReq.prob
self.recConfig = pendingReq.recConfig
self.dependencies = dependencies
self.proposition = proposition

Expand Down
Loading
Loading