Aufgrund einer Wartung wird GitLab am 18.01. zwischen 8:00 und 9:00 Uhr kurzzeitig nicht zur Verfügung stehen. / Due to maintenance, GitLab will be temporarily unavailable on 18.01. between 8:00 and 9:00 am.

Commit 9bf63f4e authored by Frederik's avatar Frederik
Browse files

created docs directory and README

parents 83a0c459 1954f4d0
......@@ -5,8 +5,6 @@
# can be found under https://github.com/MontiCore/monticore.
#
# (c) https://github.com/MontiCore/monticore
#
stages:
- windows
......
# (c) https://github.com/MontiCore/monticore
script:
- git checkout ${TRAVIS_BRANCH}
- mvn -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn -B clean install cobertura:cobertura org.eluder.coveralls:coveralls-maven-plugin:report --settings "settings.xml"
......
<!-- (c) https://github.com/MontiCore/monticore -->
# Simulation
![pipeline](https://git.rwth-aachen.de/monticore/EmbeddedMontiArc/simulators/simulation/badges/master/build.svg)
![coverage](https://git.rwth-aachen.de/monticore/EmbeddedMontiArc/simulators/simulation/badges/master/coverage.svg)
......
......@@ -16,6 +16,10 @@ import org.apache.commons.math3.exception.NullArgumentException;
import simulation.bus.BusMessage;
/**
* Abstract class that implements all common functionality of EEComponents.
*/
abstract class AbstractEEComponent implements EEComponent{
private final EESimulator simulator;
......
......@@ -16,84 +16,101 @@ import java.util.Set;
import java.time.Duration;
import org.apache.commons.lang3.tuple.Pair;
/**
* Used to connect to buses.
*/
public class Bridge extends MutableEEComponent{
protected Pair<Bus, Bus> connected;
private final Duration delay;
/**
* The two buses that should be connected
*/
protected Pair<Bus, Bus> connected;
/**
* The delay that is added to each event if it is transmitted over this bride.
*/
private final Duration delay;
public Bridge (Pair<Bus, Bus> connected, Duration delay){
super(connected.getLeft().getSimulator(), EEComponentType.BRIDGE);
if(connected.getLeft().getSimulator() != connected.getRight().getSimulator()) {
throw new IllegalArgumentException("Bus with different simulators can not be connected");
}
this.connected = connected;
this.delay = delay;
//initialize subscribed messages and targetsByMessageId
Set<BusEntry> subscribedMessages = new HashSet<BusEntry>(connected.getKey().getSubscribedMessages());
subscribedMessages.addAll(connected.getValue().getSubscribedMessages());
this.subscribedMessages.addAll(subscribedMessages);
for(BusEntry messageId : subscribedMessages) {
List<EEComponent> targets = new ArrayList<EEComponent>();
if(connected.getKey().getSubscribedMessages().contains(messageId)) {
targets.add(connected.getKey());
}
if(connected.getValue().getSubscribedMessages().contains(messageId)) {
targets.add(connected.getValue());
}
this.targetsByMessageId.put(messageId, targets);
}
connected.getKey().registerComponent(this);
connected.getValue().registerComponent(this);
}
public Bridge (Pair<Bus, Bus> connected, Duration delay){
super(connected.getLeft().getSimulator(), EEComponentType.BRIDGE);
if(connected.getLeft().getSimulator() != connected.getRight().getSimulator()) {
throw new IllegalArgumentException("Bus with different simulators can not be connected");
}
this.connected = connected;
this.delay = delay;
//initialize subscribed messages and targetsByMessageId
Set<BusEntry> subscribedMessages = new HashSet<BusEntry>(connected.getKey().getSubscribedMessages());
subscribedMessages.addAll(connected.getValue().getSubscribedMessages());
this.subscribedMessages.addAll(subscribedMessages);
for(BusEntry messageId : subscribedMessages) {
List<EEComponent> targets = new ArrayList<EEComponent>();
if(connected.getKey().getSubscribedMessages().contains(messageId)) {
targets.add(connected.getKey());
}
if(connected.getValue().getSubscribedMessages().contains(messageId)) {
targets.add(connected.getValue());
}
this.targetsByMessageId.put(messageId, targets);
}
connected.getKey().registerComponent(this);
connected.getValue().registerComponent(this);
}
@Override
public void processEvent(EEDiscreteEvent event){
if(event.getEventType() == EEDiscreteEventTypeEnum.BUSMESSAGE){
BusMessage msg = (BusMessage) event;
msg.setFinishTime(msg.getEventTime().plus(delay));
msg.transmitBytes(msg.getMessageLen(), 0);
if(msg.getControllerID() == connected.getLeft().getId()) {
this.getSimulator().addEvent(msg.forwardTo(connected.getRight()));
}
else if(msg.getControllerID() == connected.getRight().getId()) {
this.getSimulator().addEvent(msg.forwardTo(connected.getLeft()));
}
else {
throw new IllegalArgumentException("Message from invalid controller" + msg.getControllerID() + "received at: " + this.toString());
}
}
else{
throw new IllegalArgumentException("Only BusMessages events expected at " + this.toString() + " but was: " + event.getEventType());
}
}
public void processEvent(EEDiscreteEvent event){
if(event.getEventType() == EEDiscreteEventTypeEnum.BUSMESSAGE){
BusMessage msg = (BusMessage) event;
msg.setFinishTime(msg.getEventTime().plus(delay));
msg.transmitBytes(msg.getMessageLen(), 0);
if(msg.getControllerID() == connected.getLeft().getId()) {
this.getSimulator().addEvent(msg.forwardTo(connected.getRight()));
}
else if(msg.getControllerID() == connected.getRight().getId()) {
this.getSimulator().addEvent(msg.forwardTo(connected.getLeft()));
}
else {
throw new IllegalArgumentException("Message from invalid controller" + msg.getControllerID() + "received at: " + this.toString());
}
}
else{
throw new IllegalArgumentException("Only BusMessages events expected at " + this.toString() + " but was: " + event.getEventType());
}
/**
* Updates the subscribed messages of this and the other connected buses.
* Add bus as target for messages ids.
* @param bus Bus which needs the messages with messageIds
* @param messageIds Ids of messages that bus wants to receive.
*/
public void update(Bus bus, List<BusEntry> messageIds){
for(BusEntry messageId : messageIds) {
List<EEComponent> targets = this.targetsByMessageId.getOrDefault(messageId, new ArrayList<EEComponent>());
targets.add(bus);
this.targetsByMessageId.put(messageId, targets);
if(!subscribedMessages.contains(messageId)) {
this.subscribedMessages.add(messageId);
}
}
if(bus.equals(connected.getKey())){
connected.getValue().addSubscribedMessages(this, messageIds);
}
else{
if(bus.equals(connected.getValue())){
connected.getKey().addSubscribedMessages(this, messageIds);
}
else{
throw new IllegalArgumentException("Message send by unknown Bus.");
}
}
}
public void update(Bus bus, List<BusEntry> messageIds){
for(BusEntry messageId : messageIds) {
List<EEComponent> targets = this.targetsByMessageId.getOrDefault(messageId, new ArrayList<EEComponent>());
targets.add(bus);
this.targetsByMessageId.put(messageId, targets);
if(!subscribedMessages.contains(messageId)) {
this.subscribedMessages.add(messageId);
}
}
if(bus.equals(connected.getKey())){
connected.getValue().addSubscribedMessages(this, messageIds);
}
else{
if(bus.equals(connected.getValue())){
connected.getKey().addSubscribedMessages(this, messageIds);
}
else{
throw new IllegalArgumentException("Message send by unknown Bus.");
}
}
}
public Pair<Bus, Bus> getConnectedBuses() {
return this.connected;
}
public Pair<Bus, Bus> getConnectedBuses() {
return this.connected;
}
public Duration getDelay() {
return delay;
}
public Duration getDelay() {
return delay;
}
}
/**
* (c) https://github.com/MontiCore/monticore
*
* The license generally applicable for this project
* can be found under https://github.com/MontiCore/monticore.
*/
package simulation.EESimulator;
import com.google.common.collect.Sets;
import de.rwth.monticore.EmbeddedMontiArc.simulators.commons.controller.commons.BusEntry;
import de.rwth.monticore.EmbeddedMontiArc.simulators.commons.controller.interfaces.FunctionBlockInterface;
import simulation.bus.Bus;
import java.util.*;
/**
* Wrapper for a function block that always sends the messages.
*/
public class ConstantFunctionBlockAsEEComponent extends ImmutableEEComponent{
/**
* BusEntries that are send by this component by their name.
*/
private Map<String, BusEntry> busEntryByName = new HashMap<>();
/**
* Size of the message by BusEntry
*/
private final HashMap<BusEntry, Integer> sizeByMessageId;
/**
* Create a constant function block as EEComponent with default settings.
* @param buses Buses that the EEComponent should be connected
* @param sizeByMessageId Size of the messages that are transmitted
* @param functionBlock The function block that is wrapped.
* @return ConstantFunctionBlockAsEEComponent
*/
public static ConstantFunctionBlockAsEEComponent createConstantFunctionBlockAsEEComponent(List<Bus> buses, HashMap<BusEntry, Integer> sizeByMessageId, FunctionBlockInterface functionBlock){
if(buses == null || buses.isEmpty()){
throw new IllegalArgumentException("Buses can not be null or empty");
}
Set<String> outputMessageNames = functionBlock.getOutputs().keySet();
List<EEComponent> targets = new ArrayList<>(buses);
HashMap<BusEntry, List<EEComponent>> targetsByMessageId = new HashMap<>();
for(BusEntry entry : BusEntry.values()){
if(outputMessageNames.contains(entry.toString())){
targetsByMessageId.put(entry, targets);
}
}
return new ConstantFunctionBlockAsEEComponent(buses.get(0).getSimulator(), targetsByMessageId, sizeByMessageId, functionBlock);
}
/**
* Create a constant function block as EEComponent with default settings.
* @param bus Bus that the EEComponent should be connected
* @param sizeByMessageId Size of the messages that are transmitted
* @param functionBlock The function block that is wrapped.
* @return ConstantFunctionBlockAsEEComponent
*/
public static ConstantFunctionBlockAsEEComponent createConstantFunctionBlockAsEEComponent(Bus bus, HashMap<BusEntry, Integer> sizeByMessageId, FunctionBlockInterface functionBlock){
return createConstantFunctionBlockAsEEComponent(Collections.singletonList(bus), sizeByMessageId, functionBlock);
}
public ConstantFunctionBlockAsEEComponent(EESimulator simulator, HashMap<BusEntry, List<EEComponent>> targetsByMessageId, HashMap<BusEntry, Integer> sizeByMessageId, FunctionBlockInterface functionBlock) {
super(simulator, EEComponentType.FUNCTION_BLOCK, Collections.emptyList(), targetsByMessageId);
if(Sets.symmetricDifference(targetsByMessageId.keySet(), sizeByMessageId.keySet()).size() != 0){
throw new IllegalArgumentException("targetsByMessageId and sizeByMessageId have to have the same keys.");
}
for(BusEntry entry : targetsByMessageId.keySet()){
busEntryByName.put(entry.toString(), entry);
}
this.sizeByMessageId = sizeByMessageId;
this.setConstantOutput(functionBlock.getOutputs());
}
/**
* Send the constant messages by the wrapped function block
* @param outputs Messages that should be send. Indexed by the names of the message Ids.
*/
private void setConstantOutput(Map<String, Object> outputs) {
for(Map.Entry<String, Object> entry : outputs.entrySet()){
BusEntry messageId = busEntryByName.get(entry.getKey());
this.sendMessage(entry.getValue(), sizeByMessageId.get(messageId), messageId, getSimulator().getSimulationTime());
}
}
@Override
public void processEvent(EEDiscreteEvent event) {
throw new UnsupportedOperationException("Constant function block does not expect any event. Event was: " + event);
}
}
......@@ -19,10 +19,22 @@ import java.util.*;
import static com.vividsolutions.jts.util.Memory.free;
/**
* Autopilot that communicate directly with the HardwareEmulatorServer.
* Controls the velocity and path of the vehicle.
* Calculates actuator values for brakes, engine, steering.
*/
public class DirectModelAsEEComponent extends ImmutableEEComponent {
private static final int MAX_TRAJECTORY_LENGTH = 100;
/**
* Last values that were send indexed by the bus entry
*/
private Map<Object, BusEntry> lastValueByMessageId = new HashMap<>();
/**
* Necessary messages that the controller needs
*/
private static final ArrayList<BusEntry> STANDARD_SUBSCRIBED_MESSAGES = new ArrayList<BusEntry>() {{
add(BusEntry.SENSOR_VELOCITY);
add(BusEntry.SENSOR_GPS_COORDINATES);
......@@ -33,33 +45,64 @@ public class DirectModelAsEEComponent extends ImmutableEEComponent {
add(BusEntry.PLANNED_TRAJECTORY_X);
add(BusEntry.PLANNED_TRAJECTORY_Y);
}};
/**
* Outputs when created for a MassPointVehicle
*/
public static final ArrayList<BusEntry> MASSPOINT_OUTPUT_MESSAGES = new ArrayList<BusEntry>() {{
add(BusEntry.ACTUATOR_STEERING);
add(BusEntry.ACTUATOR_BRAKE);
add(BusEntry.ACTUATOR_ENGINE);
}};
/**
* Determines if the controller has received new inputs
*/
boolean newInputs = false;
/**
* Determines if the controller needs to start the calculation again afer receiving the next message.
*/
boolean wakeUpNeeded = false;
/**
* The duration of the an update cycle of this controller
*/
Duration cycleTime;
/**
* Direct reference to the hardware emulator
*/
HardwareEmulatorInterface modelServer;
int modelId;
HashMap<String, Serializable> inputs = new HashMap<String, Serializable>();
HashMap<String, Serializable> outputs = new HashMap<String, Serializable>();
Optional<Object> trajectoryX = Optional.empty();
Optional<Object> trajectoryY = Optional.empty();
Instant lastFinishTime = Instant.EPOCH;
/**
* Time when the controller was executed last
*/
Instant lastFinishTime = Instant.EPOCH;
/**
* Create a DirectModelAsEEComponent that is connected to bus.
* @param bus Bus that the DirectModelAsEEComponent is connected to
* @return DirectModelAsEEComponent with default configuration
*/
public static DirectModelAsEEComponent createDirectModelAsEEComponent(Bus bus) {
return createDirectModelAsEEComponent(Collections.singletonList(bus));
}
/**
* Create a DirectModelAsEEComponent that is connected to bus.
* @param buses Buses that the DirectModelAsEEComponent is connected to
* @return DirectModelAsEEComponent with default configuration
*/
public static DirectModelAsEEComponent createDirectModelAsEEComponent(List<Bus> buses){
HashMap<BusEntry, List<EEComponent>> targetsByMessageId = new HashMap<>();
targetsByMessageId.put(BusEntry.ACTUATOR_BRAKE, new LinkedList<>());
......@@ -101,6 +144,13 @@ public class DirectModelAsEEComponent extends ImmutableEEComponent {
}
}
/**
* Set the HardwareEmulatorInterface, create the autopilot and set the cycle time.
* @param model_server
* @param autopilot_config
* @param cycleTime
* @throws Exception
*/
public void initializeController(HardwareEmulatorInterface model_server, String autopilot_config, Duration cycleTime) throws Exception {
this.modelServer = model_server;
this.modelId = model_server.alloc_autopilot(autopilot_config);
......@@ -118,18 +168,12 @@ public class DirectModelAsEEComponent extends ImmutableEEComponent {
free();
}
/*
TODO: change time of nextExecute event
*/
@Override
public void processEvent(EEDiscreteEvent event) {
//buffer new values arrived by busMessage
if (event.getEventType() == EEDiscreteEventTypeEnum.BUSMESSAGE) {
BusMessage currentMessage = (BusMessage) event;
newInputs = true;
System.out.println("Controller received msg: " + currentMessage.getMessageID() + "; with value: " + currentMessage.getMessage());
switch (currentMessage.getMessageID()) {
case SENSOR_VELOCITY:
double currentVelocity = (double) currentMessage.getMessage();
......@@ -188,6 +232,10 @@ public class DirectModelAsEEComponent extends ImmutableEEComponent {
}
}
/**
* Execute the controller once. Add a ControllerExecuteEvent for the next cycle.
* @param event
*/
private void executeController(EEDiscreteEvent event) {
double timeIncrement = Duration.between(event.getEventTime(), lastFinishTime).toMillis();
this.inputs.put("timeIncrement", timeIncrement);
......@@ -199,20 +247,24 @@ public class DirectModelAsEEComponent extends ImmutableEEComponent {
Object engine = outputs.get("engine");
if (engine != null) {
System.out.println("Controller send msg: Engine; with value: " + engine);
this.sendMessage(engine, 8, BusEntry.ACTUATOR_ENGINE, lastFinishTime);
if(!lastValueByMessageId.containsKey(BusEntry.ACTUATOR_ENGINE) || !lastValueByMessageId.get(BusEntry.ACTUATOR_ENGINE).equals(engine)) {
this.sendMessage(engine, 8, BusEntry.ACTUATOR_ENGINE, lastFinishTime);
}
}
Object brakes = outputs.get("brakes");
if (brakes != null) {
System.out.println("Controller send msg: Brakes; with value: " + brakes);
this.sendMessage(brakes, 8, BusEntry.ACTUATOR_BRAKE, lastFinishTime);
if(!lastValueByMessageId.containsKey(BusEntry.ACTUATOR_BRAKE) || !lastValueByMessageId.get(BusEntry.ACTUATOR_BRAKE).equals(brakes)){
this.sendMessage(brakes, 8, BusEntry.ACTUATOR_BRAKE, lastFinishTime);
}
}
Object steering = outputs.get("steering");
if (steering != null) {
System.out.println("Controller send msg: Steering; with value: " + steering);
this.sendMessage(steering, 8, BusEntry.ACTUATOR_STEERING, lastFinishTime);
if(!lastValueByMessageId.containsKey(BusEntry.ACTUATOR_STEERING) || !lastValueByMessageId.get(BusEntry.ACTUATOR_STEERING).equals(steering)) {
this.sendMessage(steering, 8, BusEntry.ACTUATOR_STEERING, lastFinishTime);
}
}
//set next execute event
......
......@@ -13,13 +13,24 @@ import java.util.HashMap;
import java.util.List;
import java.util.UUID;
/**
* Components that transmit, receives, sends messages in a car.
*/
public interface EEComponent {
public EEComponentType getComponentType();
/**
* Return the messages that this component wants to receive.
* @return
*/
public List<BusEntry> getSubscribedMessages();
/**
* Return a map with registered components for each message
* @return Map with registered components for each message
*/
public HashMap<BusEntry, List<EEComponent>> getTargetsByMessageId();
public EESimulator getSimulator() ;
......@@ -34,7 +45,14 @@ public interface EEComponent {
* @return Randomly generated ID of this component
*/
public UUID getId();
/**
* Send a message to all targets registered at this component.
* @param message Message to be sent
* @param messageLen Length of the message
* @param messageId Id of the message
* @param eventTime Time when the message is send
*/
public void sendMessage(Object message, int messageLen , BusEntry messageId, Instant eventTime);
}
......@@ -14,7 +14,8 @@ public enum EEComponentType{
ACTUATOR("ACTUATOR"),
AUTOPILOT("AUTOPILOT"),
TEST_COMPONENT("TEST_COMPONENT"),
NAVIGATION("NAVIGATION");
NAVIGATION("NAVIGATION"),
FUNCTION_BLOCK("FUNCTION_BLOCK");
private final String name;
......
......@@ -9,15 +9,29 @@ package simulation.EESimulator;
import java.time.Instant;
import java.util.UUID;
/**
* Discrete Events that are processed by the EESimulator.
*/
public abstract class EEDiscreteEvent {
/**
* The time of this event
*/
private final Instant eventTime;
/**
* The target of the event
*/
private final EEComponent target;
/**
* Event type of the event
*/
private final EEDiscreteEventTypeEnum eventType;
/**
* Id of the event
*/
private final UUID Id;
public EEDiscreteEvent(EEDiscreteEventTypeEnum eventType, Instant eventTime, EEComponent target){
......
......@@ -17,6 +17,9 @@ import java.util.Comparator;
import org.jfree.util.Log;
import simulation.bus.BusMessage;
/**
* Discrete event simulator that takes care of the communication in the car.
*/
public class EESimulator {
/** Comparator for events. Sorts in ascending order of event time*/
......@@ -30,11 +33,6 @@ public class EESimulator {
*/
private PriorityQueue<EEDiscreteEvent> eventList = new PriorityQueue<>(listComparator);
/**
* lists of objects that can get addressed by messages
*/
private List<EEComponent> busList = Collections.synchronizedList(new LinkedList<>());