All files you need for this tutorial are included in the Eclipse MOSAIC zip file:
Download Eclipse MOSAIC
The Barnim: Develop Applications tutorial extends the preceding tutorial and focuses on the implementation of applications used in the Barnim scenario. In this section, the actual source code used to create the applications is explained, giving a first impression on the API of the Eclipse MOSAIC Application simulator.
After completing this tutorial you will be able to:
Develop Applications for simulation entities.
Transmit and receive V2X-messages periodically or on request depending on the network type and communication mode (e.g. Topocast, Geobroadcast, etc.).
Calculate alternative routes to the destination to circumnavigate a road obstacle.
As mentioned in Barnim: Simulation Basics, the Barnim tutorial is structured in four applications.
WeatherServer
- Broadcasts information about bad road conditions via cellular communication.WeatherWarningApp
- Detects bad road conditions, broadcasts information via ad-hoc communication, circumnavigates areas with bad road conditions.WeatherWarningAppCell
- Uses cellular communication and receives messages from WeatherServer
. Circumnavigates areas with bad road conditions.SlowDownApp
- Models driver behavior by slowing the vehicle down as soon as it enters an affected road segment.Applications can be mapped to various simulation entities, such as vehicles, servers, or traffic lights. The most basic structure for an application mapped onto a vehicle looks like the following:
public class ExampleApp extends AbstractApplication<VehicleOperatingSystem> implements VehicleApplication {
@Override
public void onStartup() {
}
@Override
public void onVehicleUpdated(VehicleData previousVehicleData, VehicleData updatedVehicleData) {
}
@Override
public void processEvent(Event event){
}
@Override
public void onShutdown() {
}
}
onVehicleUpdated
needs to be defined and overwritten in order to successfully implement the interface VehicleApplication
. processEvent
handles all events that get called to the application specific event manager, like this:
getOperatingSystem().getEventManager().addEvent(new Event(getOperatingSystem().getSimulationTime(), this));
Some examples of events are shown below, but a more detailed description can be found in the documentation.
The
WeatherServer
is a simulation unit without geographical location which has knowledge about the hazardous area and it is responsible to
transmit DEN-Messages periodically to vehicles equipped with WeatherWarningAppCell
-application via cellular communication.
Firstly, the hazardous area (Road-ID and GeoPoint coordinates), the type of the warning (Sensor type), message interval
and the resulted speed will be defined to be used later:
private final static long INTERVAL = 2 * TIME.SECOND;
private final static GeoPoint HAZARD_LOCATION = GeoPoint.latlon(52.633047, 13.565314);
private final static String HAZARD_ROAD = "-3366_2026362940_1313885502";
private final static SensorType SENSOR_TYPE = SensorType.Ice;
private final static float SPEED = 25 / 3.6f;
During the initialization procedure of communicating applications, the communication module (CellModule) needs to be
activated. This is achieved in the onStartup()
-method. The following code snippet shows the activating the
CellModule as communication mode:
public void onStartup() {
getLog().infoSimTime(this, "Initialize WeatherServer application");
getOperatingSystem().getCellModule().enable();
getLog().infoSimTime(this, "Setup weather server {} at time {}", getOs().getId(), getOs().getSimulationTime());
getLog().infoSimTime(this, "Activated Cell Module");
sample();
}
A DENM will be transmitted in 2s intervals (as configured above) to the vehicles equipped with cellular communication within reach as an event;
private void sample() {
final Denm denm = constructDenm();
getOperatingSystem().getCellModule().sendV2xMessage(denm);
getLog().infoSimTime(this, "Sent DENM");
getOperatingSystem().getEventManager().addEvent(new Event(getOperatingSystem().getSimulationTime() + INTERVAL, this));
}
The Event
created in this method is passed with a this
argument, which represents an EventProcessor
that gets notified
as soon as the proposed event time is reached. As this class implements the EventProcessor
interface, the method
processEvent()
will be called by the application simulator once the simulation time is reached:
@Override
public void processEvent(Event event) throws Exception {
sample();
}
Finally, in the method contructDenm
, the necessary data will be added to a message container DenmContent
and we create
a circular area for the rerouting (3000 m) of the DEN-Message as Broadcast. All vehicles within this area which
have the cellular module activated, will receive this message.
private Denm constructDenm() {
final GeoCircle geoCircle = new GeoCircle(HAZARD_LOCATION, 3000.0D);
final MessageRouting routing = getOperatingSystem().getCellModule().createMessageRouting().geoBroadCast(geoCircle);
final int strength = getOperatingSystem().getStateOfEnvironmentSensor(SENSOR_TYPE);
return new Denm(routing,
new DenmContent(
getOperatingSystem().getSimulationTime(),
null,
HAZARD_ROAD,
SENSOR_TYPE,
strength,
SPEED,
0.0f,
HAZARD_LOCATION,
null,
null
)
);
}
The
WeatherWarningApp
application illustrates the vehicles and their behaviour in particular with regard to the
detecting hazardous area, the receiving and sending messages. We will also cover how alternative routes
will be calculated and how vehicles change their route in order to circumnavigate the affected road area.
The simulating vehicles can be operated as Cellular or Ad-hoc equipped. Accordingly, the kind of used communication
network will be activated in the onStartup()
method as following:
public void onStartup() {
getLog().infoSimTime(this, "Initialize application");
if (useCellNetwork()) {
getOperatingSystem().getCellModule().enable();
getLog().infoSimTime(this, "Activated Cell Module");
} else {
getOperatingSystem().getAdHocModule().enable(new AdHocModuleConfiguration()
.addRadio()
.channel(AdHocChannel.CCH)
.power(50)
.create());
getLog().infoSimTime(this, "Activated AdHoc Module");
}
getOperatingSystem().requestVehicleParametersUpdate()
.changeColor(Color.RED)
.apply();
}
In case the sensor detects an environmental hazard the vehicle sends out a DEN-message to warn
other vehicles. In the reactOnEnvironmentData()
method, the sending is handled with
regard to used communication network. If WeatherWarningAppCell
is mapped, cellular communication is used,
in case of WeatherWarningApp
ITS-G5 communication is used as described in the
Tiergarten: Communication Tutorial.
private void reactOnEnvironmentData(SensorType type, int strength) {
GeoPoint vehiclePosition = getOperatingSystem().getPosition();
String roadId = getOperatingSystem().getVehicleInfo().getRoadPosition().getConnection().getId();
// reach all vehicles in a 3000m radius
GeoCircle dest = new GeoCircle(vehiclePosition, 3000);
MessageRouting mr;
if (useCellNetwork()) {
mr = getOperatingSystem().getCellModule().createMessageRouting().geoBroadCast(dest);
} else {
mr = getOperatingSystem().getAdHocModule().createMessageRouting().geoBroadCast(dest);
}
Denm denm = new Denm(mr, new DENMContent(
getOperatingSystem().getSimulationTime(), vehiclePosition, roadId, type, strength, SPEED, 0.0f, vehiclePosition, null, null)
);
if (useCellNetwork()) {
getOperatingSystem().getCellModule().sendV2XMessage(denm);
} else {
getOperatingSystem().getAdHocModule().sendV2XMessage(denm);
}
}
Next, we look at the receiving side of the DENM here. Since the message is a simple V2X message it
is received through the receiveV2xMessage()
-method which is part of the application interface.
Analogous to a normal message, here we check with instanceof
, if it is of a type that we are interested in, in
this case Denm
. In that very case, we perform a potential route change if not already done.
public void receiveV2xMessage(ReceivedV2xMessage receivedV2xMessage) {
final V2xMessage msg = receivedV2xMessage.getMessage();
if (!(msg instanceof Denm)) {
return;
}
final Denm denm = (Denm)msg;
if (routeChanged) {
getLog().infoSimTime(this, "Route already changed");
} else {
reactUponDENMessageChangeRoute(denm);
}
}
In order to calculate alternative routes to the destination and to change the actual route to the next best route,
the method circumnavigateAffectedRoad()
is implemented. The affected road segment is identified by the road id parameter.
The route calculation needs to be parametrized in a way, that it avoids this road segment to include in the calculation.
This is achieved by using the specific cost function ReRouteSpecificConnectionsCostFunction
and passing it
to the RoutingParameters
object.
private void circumnavigateAffectedRoad(DENM denm, final String affectedRoadId) {
ReRouteSpecificConnectionsCostFunction myCostFunction = new ReRouteSpecificConnectionsCostFunction();
myCostFunction.setConnectionSpeedMS(affectedRoadId, denm.getCausedSpeed());
INavigationModule navigationModule = getOperatingSystem().getNavigationModule();
RoutingParameters routingParameters = new RoutingParameters().costFunction(myCostFunction);
RoutingResponse response = navigationModule.calculateRoutes(new RoutingPosition(navigationModule.getTargetPosition()), routingParameters);
CandidateRoute newRoute = response.getBestRoute();
if (newRoute != null) {
getLog().infoSimTime(this, "Sending Change Route Command at position: {}", denm.getSenderPosition());
navigationModule.switchRoute(newRoute);
}
}
The only difference of the
WeatherWarningAppCell
to detailed described WeatherWarningApp is that the
WeatherWarningAppCell
-application enabled the use of the cellular network.
The
SlowDownApp
induces a speed reduction as soon as the on-board sensors detect hazardous conditions.
To detect the change in the on-board sensors, the state of the sensors have to be queried whenever the
vehicle has moved. This is achieved by implementing the onVehicleUpdated()
method which is called
whenever the traffic simulator executed one simulation step.
In this specific implementation, the speed of the vehicle is reduced to 25 km/h within the entire hazardous area. After leaving the hazardous area, the vehicles returns to their original speed again:
public void onVehicleUpdated(VehicleData previousVehicleData, VehicleData updatedVehicleData) {
SensorType[] types = SensorType.values();
int strength = 0;
for (SensorType currentType : types) {
strength = getOs().getStateOfEnvironmentSensor(currentType);
if (strength > 0) {
break;
}
}
if (strength > 0 && !hazardousArea) {
getOs().changeSpeedWithInterval(SPEED, 5000);
hazardousArea = true;
}
if (strength == 0 && hazardousArea) {
getOs().resetSpeed();
hazardousArea = false;
}
}