Skip to content

Commit

Permalink
feat(application): introduce agent unit and agent operating system
Browse files Browse the repository at this point in the history
* spawning of agents via mapping_config.json
* creating agent units in mosaic-application
* provide AgentOperatingSystem with access to public transport routing and other really basic API
* still no functionality, as the core Agent-Simulator is still missing
  • Loading branch information
kschrab committed Jan 15, 2025
1 parent 2cf33c8 commit cc7f6c1
Show file tree
Hide file tree
Showing 36 changed files with 1,082 additions and 345 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import org.eclipse.mosaic.interactions.electricity.VehicleChargingDenial;
import org.eclipse.mosaic.interactions.environment.EnvironmentSensorUpdates;
import org.eclipse.mosaic.interactions.environment.LidarUpdates;
import org.eclipse.mosaic.interactions.mapping.AgentRegistration;
import org.eclipse.mosaic.interactions.mapping.ChargingStationRegistration;
import org.eclipse.mosaic.interactions.mapping.RsuRegistration;
import org.eclipse.mosaic.interactions.mapping.ServerRegistration;
Expand Down Expand Up @@ -266,6 +267,8 @@ protected void processInteraction(final Interaction interaction) throws Internal
this.process((RsuRegistration) interaction);
} else if (interaction.getTypeId().startsWith(ChargingStationRegistration.TYPE_ID)) {
this.process((ChargingStationRegistration) interaction);
} else if (interaction.getTypeId().startsWith(AgentRegistration.TYPE_ID)) {
this.process((AgentRegistration) interaction);
} else if (interaction.getTypeId().startsWith(TrafficLightRegistration.TYPE_ID)) {
this.process((TrafficLightRegistration) interaction);
} else if (interaction.getTypeId().startsWith(VehicleRegistration.TYPE_ID)) {
Expand Down Expand Up @@ -373,6 +376,10 @@ private void process(final TrafficLightRegistration trafficLightRegistration) {
.addTrafficLightGroup(trafficLightRegistration.getTrafficLightGroup());
}

private void process(final AgentRegistration agentRegistration) {
UnitSimulator.UnitSimulator.registerAgent(agentRegistration);
}

private void process(final VehicleRegistration vehicleRegistration) {
String vehicleName = vehicleRegistration.getMapping().getName();
vehicleRegistrations.put(vehicleName, vehicleRegistration);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,10 @@ public enum ErrorRegister {
TRAFFIC_MANAGEMENT_CENTER_NoEventResource(0x01000091, "Process event with no resource."),
// 0x01000100 to 0x0100010F Servers
SERVER_UnknownEvent(0x01000100, "Process unknown event."),
SERVER_NoEventResource(0x0100101, "Process event with no resource.");
SERVER_NoEventResource(0x0100101, "Process event with no resource."),
// 0x01000110 to 0x0100011F Agents
AGENT_UnknownEvent(0x01000110, "Process unknown event."),
AGENT_NoEventResource(0x0100111, "Process event with no resource.");

/**
* The code of the error.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.eclipse.mosaic.fed.application.ambassador.eventresources.RemoveVehicles;
import org.eclipse.mosaic.fed.application.ambassador.eventresources.StartApplications;
import org.eclipse.mosaic.fed.application.ambassador.simulation.AbstractSimulationUnit;
import org.eclipse.mosaic.fed.application.ambassador.simulation.AgentUnit;
import org.eclipse.mosaic.fed.application.ambassador.simulation.ChargingStationUnit;
import org.eclipse.mosaic.fed.application.ambassador.simulation.ElectricVehicleUnit;
import org.eclipse.mosaic.fed.application.ambassador.simulation.RoadSideUnit;
Expand All @@ -26,6 +27,7 @@
import org.eclipse.mosaic.fed.application.ambassador.simulation.TrafficManagementCenterUnit;
import org.eclipse.mosaic.fed.application.ambassador.simulation.VehicleUnit;
import org.eclipse.mosaic.interactions.environment.EnvironmentSensorActivation;
import org.eclipse.mosaic.interactions.mapping.AgentRegistration;
import org.eclipse.mosaic.interactions.mapping.ChargingStationRegistration;
import org.eclipse.mosaic.interactions.mapping.RsuRegistration;
import org.eclipse.mosaic.interactions.mapping.ServerRegistration;
Expand Down Expand Up @@ -92,6 +94,11 @@ public enum UnitSimulator implements EventProcessor {
*/
private final Map<String, VehicleUnit> vehicles = new HashMap<>();

/**
* Map containing all the ids with the corresponding agent units.
*/
private final Map<String, AgentUnit> agents = new HashMap<>();

/**
* Map containing all the ids with the corresponding {@link AbstractSimulationUnit}.
*/
Expand Down Expand Up @@ -133,6 +140,15 @@ public Map<String, VehicleUnit> getVehicles() {
return vehicles;
}

/**
* Returns the map containing all the ids with the corresponding agents.
*
* @return the map containing all the ids with the corresponding agents.
*/
public Map<String, AgentUnit> getAgents() {
return agents;
}

/**
* Returns the map containing all the ids with the corresponding TMCs.
*
Expand Down Expand Up @@ -186,6 +202,8 @@ private void addSimulationUnit(final AbstractSimulationUnit unit) {
servers.put(unit.getId(), server);
} else if (unit instanceof VehicleUnit vehicle) {
vehicles.put(unit.getId(), vehicle);
} else if (unit instanceof AgentUnit agent) {
agents.put(unit.getId(), agent);
} else {
throw new RuntimeException(ErrorRegister.UNIT_SIMULATOR_UnknownSimulationUnitToPutInMap.toString());
}
Expand Down Expand Up @@ -213,6 +231,8 @@ private void removeSimulationUnit(final AbstractSimulationUnit unit) {
servers.remove(unit.getId());
} else if (unit instanceof VehicleUnit) {
vehicles.remove(unit.getId());
} else if (unit instanceof AgentUnit) {
agents.remove(unit.getId());
} else {
throw new RuntimeException(ErrorRegister.UNIT_SIMULATOR_UnknownSimulationUnitToRemoveFromMap.toString());
}
Expand All @@ -236,6 +256,7 @@ public void removeAllSimulationUnits() {
vehicles.clear();
tmcs.clear();
servers.clear();
agents.clear();
allUnits.clear();
}

Expand Down Expand Up @@ -455,6 +476,30 @@ private void doSensorRegistration(final long time, final String id) {
simulationUnit.sendInteractionToRti(environmentSensorActivation);
}


/**
* Registers an Agent. Unit is only registered if it is equipped with an application
*
* @param agentRegistration the interaction containing the mapping of the agent
*/
public void registerAgent(AgentRegistration agentRegistration) {
if (!agentRegistration.getMapping().hasApplication()) {
log.warn("An agent will not move without any application.");
return;
}
final AgentUnit agent = new AgentUnit(agentRegistration.getMapping(), agentRegistration.getOrigin(), agentRegistration.getDestination());
agent.setGroup(agentRegistration.getMapping().getGroup());

addSimulationUnit(agent);

final Event event = new Event(
agentRegistration.getTime(),
this, new StartApplications(agent.getId(), agentRegistration.getMapping()),
Event.NICE_MAX_PRIORITY
);
SimulationKernel.SimulationKernel.getEventManager().addEvent(event);
}

@Override
public void processEvent(Event event) {
final Object resource = event.getResource();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
/*
* Copyright (c) 2025 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: [email protected]
*/

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

import org.eclipse.mosaic.fed.application.ambassador.ErrorRegister;
import org.eclipse.mosaic.fed.application.ambassador.SimulationKernel;
import org.eclipse.mosaic.fed.application.ambassador.simulation.communication.CamBuilder;
import org.eclipse.mosaic.fed.application.ambassador.simulation.navigation.AgentPtRoutingModule;
import org.eclipse.mosaic.fed.application.ambassador.simulation.navigation.RoutingNavigationModule;
import org.eclipse.mosaic.fed.application.app.api.navigation.PtRoutingModule;
import org.eclipse.mosaic.fed.application.app.api.navigation.RoutingModule;
import org.eclipse.mosaic.fed.application.app.api.os.AgentOperatingSystem;
import org.eclipse.mosaic.interactions.agent.AgentRouteChange;
import org.eclipse.mosaic.lib.geo.GeoPoint;
import org.eclipse.mosaic.lib.objects.agent.AgentRoute;
import org.eclipse.mosaic.lib.objects.mapping.AgentMapping;
import org.eclipse.mosaic.lib.objects.vehicle.VehicleDeparture;
import org.eclipse.mosaic.lib.objects.vehicle.VehicleRoute;
import org.eclipse.mosaic.lib.routing.CandidateRoute;
import org.eclipse.mosaic.lib.routing.IllegalRouteException;
import org.eclipse.mosaic.lib.routing.pt.PtRoute;
import org.eclipse.mosaic.lib.util.scheduling.Event;

import com.google.common.collect.Lists;

import java.util.List;

public class AgentUnit extends AbstractSimulationUnit implements AgentOperatingSystem {

private final RoutingModule vehicleRoutingModule;
private final PtRoutingModule ptRoutingModule;
private final GeoPoint originPosition;
private final GeoPoint destinationPosition;

public AgentUnit(AgentMapping agentMapping, final GeoPoint originPosition, final GeoPoint destinationPosition) {
super(agentMapping.getName(), originPosition);
setRequiredOperatingSystem(AgentOperatingSystem.class);

vehicleRoutingModule = new RoutingNavigationModule(this);
ptRoutingModule = new AgentPtRoutingModule(agentMapping.getWalkingSpeed());

this.originPosition = originPosition;
this.destinationPosition = destinationPosition;
}

@Override
public void usePrivateVehicle(String vehicleType, CandidateRoute route) {
try {
VehicleRoute rtiRoute = SimulationKernel.SimulationKernel.getCentralNavigationComponent().createAndPropagateRoute(
route, getSimulationTime()
);

if (rtiRoute == null) {
throw new IllegalRouteException("Provided route could not be propagated to RTI.");
}

final List<AgentRoute.Leg> agentLegs = Lists.newArrayList(new AgentRoute.PrivateVehicleLeg(
getSimulationTime(),
vehicleType,
new VehicleDeparture.Builder(rtiRoute.getId())
.departureSpeed(VehicleDeparture.DepartureSpeedMode.PRECISE, 0)
.create()
));
sendInteractionToRti(new AgentRouteChange(
getSimulationTime(), getId(), new AgentRoute(agentLegs)
));

} catch (IllegalRouteException e) {
throw new RuntimeException("Invalid route provided.", e);
}
}

@Override
public void useSharedVehicle(String vehicleId) {
final List<AgentRoute.Leg> agentLegs = Lists.newArrayList(new AgentRoute.SharedVehicleLeg(
getSimulationTime(),
vehicleId
));

sendInteractionToRti(new AgentRouteChange(
getSimulationTime(), getId(), new AgentRoute(agentLegs)
));
}

@Override
public void usePublicTransport(PtRoute publicTransportRoute) {
final List<AgentRoute.Leg> agentLegs = publicTransportRoute.getLegs().stream().map(leg -> {
if (leg instanceof PtRoute.PtLeg ptLeg) {
return new AgentRoute.PublicTransportLeg(leg.getDepartureTime(), ptLeg.getStops());
}
if (leg instanceof PtRoute.WalkLeg walkLeg) {
return new AgentRoute.WalkLeg(leg.getDepartureTime(), walkLeg.getWaypoints());
}
throw new IllegalArgumentException("Unsupported leg type found in public transport route.");
}).toList();

if (agentLegs.isEmpty()) {
return;
}
sendInteractionToRti(new AgentRouteChange(
getSimulationTime(), getId(), new AgentRoute(agentLegs)
));
}

@Override
public GeoPoint getOriginPosition() {
return originPosition;
}

@Override
public GeoPoint getDestinationPosition() {
return destinationPosition;
}

@Override
public PtRoutingModule getPtRoutingModule() {
return ptRoutingModule;
}

@Override
public RoutingModule getRoutingModule() {
return vehicleRoutingModule;
}

@Override
public void processEvent(Event event) throws Exception {
// never remove the preProcessEvent call!
final boolean preProcessed = super.preProcessEvent(event);

// failsafe
if (preProcessed) {
return;
}

final Object resource = event.getResource();

// failsafe
if (resource == null) {
getOsLog().error("Event has no resource: {}", event);
throw new RuntimeException(ErrorRegister.AGENT_NoEventResource.toString());
}

getOsLog().error("Unknown event resource: {}", event);
throw new RuntimeException(ErrorRegister.AGENT_UnknownEvent.toString());
}

@Override
public CamBuilder assembleCamMessage(CamBuilder camBuilder) {
throw new UnsupportedOperationException("Agents are not able to send CAMs");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2025 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: [email protected]
*/

package org.eclipse.mosaic.fed.application.ambassador.simulation.navigation;

import org.eclipse.mosaic.fed.application.ambassador.SimulationKernel;
import org.eclipse.mosaic.fed.application.app.api.navigation.PtRoutingModule;
import org.eclipse.mosaic.lib.geo.GeoPoint;
import org.eclipse.mosaic.lib.routing.pt.PtRoutingParameters;
import org.eclipse.mosaic.lib.routing.pt.PtRoutingRequest;
import org.eclipse.mosaic.lib.routing.pt.PtRoutingResponse;

public class AgentPtRoutingModule implements PtRoutingModule {

private final double defaultWalkingSpeed;

public AgentPtRoutingModule(double defaultWalkingSpeed) {
this.defaultWalkingSpeed = defaultWalkingSpeed;
}

@Override
public PtRoutingResponse calculateRoute(long requestTime, GeoPoint origin, GeoPoint destination, PtRoutingParameters routingParameters) {
PtRoutingRequest routingRequest = new PtRoutingRequest(requestTime, origin, destination, routingParameters);
if (routingParameters.getWalkingSpeedMps() == null) {
routingParameters.walkingSpeedMps(defaultWalkingSpeed);
}
return SimulationKernel.SimulationKernel.getCentralNavigationComponent().findPtRoute(routingRequest);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -247,23 +247,35 @@ public VehicleRoute switchRoute(VehicleData vehicleData, CandidateRoute rawRoute
return requestStaticRouteChange(vehicleData, knownRoute, currentRoute, time);
} else {
// generate a new route
VehicleRoute route = vehicleRouting.createRouteForRTI(rawRoute);

// propagate the new route
try {
log.debug("Propagate unknown route {}.", route.getId());
propagateRoute(route, time);
} catch (InternalFederateException e) {
log.error("[CNC.switchRoute]: unable to send propagate a new route.");
VehicleRoute route = createAndPropagateRoute(rawRoute, time);

if (route == null) {
log.error("[CNC.switchRoute]: unable to propagate new route.");
return currentRoute;
}

// change route for sumo
return requestStaticRouteChange(vehicleData, route, currentRoute, time);
}
}
}

/**
* Creates a {@link VehicleRoute} from a {@link CandidateRoute} and propagates it
* to all ambassadors by triggering a {@link VehicleRouteRegistration}.
*
* @param rawRoute The raw route object.
* @param time The current simulation time. Used when sending the {@link VehicleRouteRegistration}.
*/
public VehicleRoute createAndPropagateRoute(CandidateRoute rawRoute, long time) throws IllegalRouteException {
VehicleRoute route = vehicleRouting.createRouteForRTI(rawRoute);
try {
log.debug("Propagate unknown route {}.", route.getId());
propagateRoute(route, time);
return route;
} catch (InternalFederateException e) {
return null;
}
}

/**
* Helper-method for {@link #switchRoute}.
*
Expand Down
Loading

0 comments on commit cc7f6c1

Please sign in to comment.