Skip to content

Commit

Permalink
feat(perception): simplified configuration for perception index (#351)
Browse files Browse the repository at this point in the history
* feat: simplified configuration for perception index
* use separate configuration class instead of inferring index implementations with configuration
* removed simple index implementation based on for-loops, keep tree,grid,sumo as vehicle index implementations
* removed measurement of index performance
* simplified configuration of indexes, e.g. by enabling/disabling them via config option
* use tree implementation for vehicle index by default
* all indexes are disabled by default
* use parametrized test instead of repeating test methods in SimplePerceptionModuleTest
* fix: remove unused configuration option
* feat: add example perception config for Barnim
* fix: resolve spotbugs warning
* feat: add perception modifier for heading and dimensions
* clean: use convenient order of dimension attributes
* feat: enable vehicle index by default
  • Loading branch information
kschrab authored Oct 4, 2023
1 parent 4c3b72d commit 3551890
Show file tree
Hide file tree
Showing 36 changed files with 672 additions and 716 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"messageCacheTime": "30s",
"encodePayloads": true,
"eventSchedulerThreads": 1,
"navigationConfiguration": {
"type": "database"
},
"perceptionConfiguration": {
"vehicleIndex": {
"enabled": true
},
"trafficLightIndex": {
"enabled": true
},
"wallIndex": {
"enabled": false
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -369,8 +369,10 @@ this, new StartApplications(chargingStationUnit.getId(), chargingStationRegistra
* @param trafficLightRegistration traffic light
*/
public void registerTrafficLight(TrafficLightRegistration trafficLightRegistration) {
if (!trafficLightRegistration.getMapping().hasApplication()
&& SimulationKernel.SimulationKernel.getConfiguration().perceptionConfiguration.trafficLightIndex == null) {
// if traffic light index is enabled, we need traffic light state information for all traffic lights via subscriptions
boolean isTrafficLightIndexEnabled = SimulationKernel.SimulationKernel.getConfiguration().perceptionConfiguration.trafficLightIndex != null &&
SimulationKernel.SimulationKernel.getConfiguration().perceptionConfiguration.trafficLightIndex.enabled;
if (!trafficLightRegistration.getMapping().hasApplication() && !isTrafficLightIndexEnabled) {
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,13 @@ public VehicleUnit(String vehicleName, VehicleType vehicleType, final GeoPoint i
.getCentralNavigationComponent().getRouting()).getScenarioDatabase();
}

if (SimulationKernel.SimulationKernel.getConfiguration().perceptionConfiguration.vehicleIndex != null) {
perceptionModule = SimulationKernel.SimulationKernel.getConfiguration().perceptionConfiguration.vehicleIndex
.createPerceptionModule(this, database, getOsLog());
if (SimulationKernel.SimulationKernel.getCentralPerceptionComponent().getTrafficObjectIndex() != null) {
perceptionModule = SimulationKernel.SimulationKernel.getCentralPerceptionComponent()
.getTrafficObjectIndex().createPerceptionModule(this, database, getOsLog());
} else {
perceptionModule = new NopPerceptionModule(this, database, getOsLog());
}

}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,34 +17,21 @@

import org.eclipse.mosaic.fed.application.ambassador.SimulationKernel;
import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.index.TrafficObjectIndex;
import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.index.objects.TrafficLightObject;
import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.index.objects.VehicleObject;
import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.index.providers.TrafficLightMap;
import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.index.providers.VehicleMap;
import org.eclipse.mosaic.fed.application.config.CApplicationAmbassador;
import org.eclipse.mosaic.fed.application.config.CPerception;
import org.eclipse.mosaic.interactions.traffic.TrafficLightUpdates;
import org.eclipse.mosaic.interactions.traffic.VehicleUpdates;
import org.eclipse.mosaic.lib.database.Database;
import org.eclipse.mosaic.lib.geo.CartesianRectangle;
import org.eclipse.mosaic.lib.math.Vector3d;
import org.eclipse.mosaic.lib.objects.trafficlight.TrafficLightGroup;
import org.eclipse.mosaic.lib.objects.trafficlight.TrafficLightGroupInfo;
import org.eclipse.mosaic.lib.objects.vehicle.VehicleData;
import org.eclipse.mosaic.lib.objects.vehicle.VehicleType;
import org.eclipse.mosaic.lib.routing.Routing;
import org.eclipse.mosaic.lib.spatial.Edge;
import org.eclipse.mosaic.lib.util.PerformanceMonitor;
import org.eclipse.mosaic.rti.api.InternalFederateException;

import com.google.common.collect.Iterables;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
* The {@link CentralPerceptionComponent} is responsible for keeping a spatial index of all vehicles,
* which allows fast querying of nearby vehicles.
Expand All @@ -57,7 +44,7 @@ public class CentralPerceptionComponent {
/**
* Configuration containing parameters for setting up the spatial indexes.
*/
private final CApplicationAmbassador.CPerception configuration;
private final CPerception configuration;

/**
* The spatial index used to store and find objects by their positions.
Expand All @@ -84,7 +71,7 @@ public class CentralPerceptionComponent {
*/
private boolean updateTrafficLightIndex = false;

public CentralPerceptionComponent(CApplicationAmbassador.CPerception perceptionConfiguration) {
public CentralPerceptionComponent(CPerception perceptionConfiguration) {
this.configuration = Validate.notNull(perceptionConfiguration, "perceptionConfiguration must not be null");
}

Expand All @@ -99,38 +86,21 @@ public void initialize() throws InternalFederateException {
// evaluate bounding box for perception
scenarioBounds = configuration.perceptionArea == null
? routing.getScenarioBounds() : configuration.perceptionArea.toCartesian();
// see what backends are configured
boolean vehicleIndexConfigured = configuration.vehicleIndex != null;
boolean trafficLightIndexConfigured = configuration.trafficLightIndex != null;

TrafficObjectIndex.Builder indexBuilder = new TrafficObjectIndex.Builder(LOG);
if (scenarioBounds.getArea() <= 0) {
LOG.warn("The bounding area of the scenario could not be determined. Defaulting to low performance spatial index.");
if (vehicleIndexConfigured) { // if configured default to map index
indexBuilder.withVehicleIndex(new VehicleMap());
}
if (trafficLightIndexConfigured) { // if configured default to map index
indexBuilder.withTrafficLightIndex(new TrafficLightMap());
}
} else {
if (vehicleIndexConfigured) {
indexBuilder.withVehicleIndex(configuration.vehicleIndex);
}
if (trafficLightIndexConfigured) {
indexBuilder.withTrafficLightIndex(configuration.trafficLightIndex);
}
if (configuration.vehicleIndex != null) {
indexBuilder.withVehicleIndex(configuration.vehicleIndex.create());
}
if (configuration.trafficLightIndex != null) {
indexBuilder.withTrafficLightIndex(configuration.trafficLightIndex.create());
}
if (routing instanceof Database) {
Database dbRouting = (Database) routing;
if (!dbRouting.getBuildings().isEmpty()) {
indexBuilder.withWallIndex(configuration.wallIndex, (Database) routing);
if (!dbRouting.getBuildings().isEmpty() && configuration.wallIndex != null) {
indexBuilder.withWallIndex(configuration.wallIndex.create(), (Database) routing);
}
}
trafficObjectIndex = indexBuilder.build();

if (configuration.measurePerformance) {
trafficObjectIndex = new MonitoringTrafficObjectIndexProvider(trafficObjectIndex, PerformanceMonitor.getInstance());
}
} catch (Exception e) {
throw new InternalFederateException("Couldn't initialize CentralPerceptionComponent", e);
}
Expand Down Expand Up @@ -212,63 +182,4 @@ public void updateTrafficLights(TrafficLightUpdates trafficLightUpdates) {
updateTrafficLightIndex = true;
}

/**
* Wrapper class to measure atomic calls of update, search and remove of the used spatial index.
*/
static class MonitoringTrafficObjectIndexProvider extends TrafficObjectIndex {
private final PerformanceMonitor monitor;

MonitoringTrafficObjectIndexProvider(TrafficObjectIndex parent, PerformanceMonitor monitor) {
super(parent);
this.monitor = monitor;
}

@Override
public List<VehicleObject> getVehiclesInRange(PerceptionModel searchRange) {
try (PerformanceMonitor.Measurement m = monitor.start("search-vehicle")) {
m.setProperties(getNumberOfVehicles(), SimulationKernel.SimulationKernel.getCurrentSimulationTime()).restart();
return super.getVehiclesInRange(searchRange);
}
}

@Override
public void removeVehicles(Iterable<String> vehiclesToRemove) {
try (PerformanceMonitor.Measurement m = monitor.start("remove-vehicle")) {
m.setProperties(getNumberOfVehicles(), SimulationKernel.SimulationKernel.getCurrentSimulationTime()).restart();
super.removeVehicles(vehiclesToRemove);
}
}

@Override
public void updateVehicles(Iterable<VehicleData> vehiclesToUpdate) {
try (PerformanceMonitor.Measurement m = monitor.start("update-vehicle")) {
m.setProperties(getNumberOfVehicles(), SimulationKernel.SimulationKernel.getCurrentSimulationTime()).restart();
super.updateVehicles(vehiclesToUpdate);
}
}

@Override
public List<TrafficLightObject> getTrafficLightsInRange(PerceptionModel perceptionModel) {
try (PerformanceMonitor.Measurement m = monitor.start("search-traffic-light")) {
m.setProperties(SimulationKernel.SimulationKernel.getCurrentSimulationTime()).restart();
return super.getTrafficLightsInRange(perceptionModel);
}
}

@Override
public void updateTrafficLights(Map<String, TrafficLightGroupInfo> trafficLightsToUpdate) {
try (PerformanceMonitor.Measurement m = monitor.start("update-traffic-light")) {
m.setProperties(SimulationKernel.SimulationKernel.getCurrentSimulationTime()).restart();
super.updateTrafficLights(trafficLightsToUpdate);
}
}

@Override
public Collection<Edge<Vector3d>> getSurroundingWalls(PerceptionModel perceptionModel) {
try (PerformanceMonitor.Measurement m = monitor.start("search-walls")) {
m.setProperties(SimulationKernel.SimulationKernel.getCurrentSimulationTime()).restart();
return super.getSurroundingWalls(perceptionModel);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Copyright (c) 2022 Fraunhofer FOKUS and others. All rights reserved.
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*
* Contact: mosaic@fokus.fraunhofer.de
*/

package org.eclipse.mosaic.fed.application.ambassador.simulation.perception.errormodels;

import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.PerceptionModuleOwner;
import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.index.objects.SpatialObject;
import org.eclipse.mosaic.fed.application.ambassador.simulation.perception.index.objects.VehicleObject;
import org.eclipse.mosaic.lib.math.MathUtils;
import org.eclipse.mosaic.lib.math.RandomNumberGenerator;
import org.eclipse.mosaic.lib.math.Vector3d;
import org.eclipse.mosaic.lib.math.VectorUtils;

import java.util.List;

/**
* Adjusts the dimensions of perceived {@link VehicleObject}s. Since the position
* of vehicles is assumed to refer to their front bumper instead of bounding box center,
* their position is adjusted accordingly when the length of the vehicle was changed.
*/
public class DimensionsModifier implements PerceptionModifier {

private static final double SIGMA_WIDTH_OFFSET = 0.2; // given in m
private static final double SIGMA_HEIGHT_OFFSET = 0.2; // given in m
private static final double SIGMA_LENGTH_OFFSET = 0.5; // given in m

private final double heightDeviation;
private final double widthDeviation;
private final double lengthDeviation;

private final RandomNumberGenerator rng;


public DimensionsModifier(RandomNumberGenerator rng, double lengthDeviation, double widthDeviation, double heightDeviation) {
this.rng = rng;
this.lengthDeviation = lengthDeviation;
this.widthDeviation = widthDeviation;
this.heightDeviation = heightDeviation;
}

public DimensionsModifier(RandomNumberGenerator rng) {
this.rng = rng;
this.lengthDeviation = SIGMA_LENGTH_OFFSET;
this.widthDeviation = SIGMA_WIDTH_OFFSET;
this.heightDeviation = SIGMA_HEIGHT_OFFSET;
}

@Override
public <T extends SpatialObject> List<T> apply(PerceptionModuleOwner owner, List<T> spatialObjects) {
spatialObjects.stream()
.filter(o -> o instanceof VehicleObject)
.forEach(o -> adjustDimensionsOfVehicle((VehicleObject) o));
return spatialObjects;
}

private void adjustDimensionsOfVehicle(VehicleObject vehicleObject) {

double oldLength = vehicleObject.getLength();

vehicleObject.setDimensions(
Math.abs(rng.nextGaussian(vehicleObject.getLength(), lengthDeviation)),
Math.abs(rng.nextGaussian(vehicleObject.getWidth(), widthDeviation)),
Math.abs(rng.nextGaussian(vehicleObject.getHeight(), heightDeviation))
);

double newLength = vehicleObject.getLength();

if (MathUtils.isFuzzyEqual(newLength, oldLength)) {
return;
}

// move position of vehicle based on length difference since vehicle position is assumed to refer to front bumper and we want to
// squeeze the length around bounding box center
Vector3d direction = VectorUtils.getDirectionVectorFromHeading(vehicleObject.getHeading(), new Vector3d())
.multiply((newLength - oldLength) / 2);
vehicleObject.setPosition(
vehicleObject.getPosition().x + direction.x,
vehicleObject.getPosition().y + direction.y,
vehicleObject.getPosition().z + direction.z
);
}

}

Loading

0 comments on commit 3551890

Please sign in to comment.