Commit eac3bfb7 authored by Jean Meurice's avatar Jean Meurice
Browse files

Update 3.0.0: 'ComponentRework'

parents d81cbca0 8f6997f0
Pipeline #336481 passed with stage
in 1 minute and 12 seconds
......@@ -11,4 +11,5 @@
*logs*
.flattened-pom.xml
.vscode/
./lib/
\ No newline at end of file
./lib/
**/vis
\ No newline at end of file
#
# (c) https://github.com/MontiCore/monticore
#
# The license generally applicable for this project
# can be found under https://github.com/MontiCore/monticore.
#
stages:
......@@ -11,46 +6,44 @@ stages:
- linux
- integration-test
#masterJobLinux:
# stage: linux
# image: maven:3.6-jdk-8
# before_script:
# - apt-get update
# - apt-get install -y openjfx
# script:
# - mv lib/fmu_for_linux/*.fmu lib/
# - mvn -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn -B clean deploy sonar:sonar --settings settings.xml
## - cat report/target/coverage-report/html/index.html
# only:
# - master
masterJobWindows:
stage: windows
script:
- mvn -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn -B clean deploy --settings settings.xml
- mvn package sonar:sonar -s settings.xml
tags:
- Windows10_OS
only:
- master
branchJobWindows:
stage: windows
script:
- mvn -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn -B clean install --settings settings.xml
tags:
- Windows10_OS
except:
MasterJobLinux:
stage: linux
image: maven:3-jdk-8
script:
- mvn -B clean deploy sonar:sonar -s settings.xml
#- cat report/target/coverage-report/html/index.html
only:
- master
# BranchJobLinux:
# stage: linux
# image: hwzzz/openjdk-openjfx:latest
BranchJobLinux:
stage: linux
image: maven:3-jdk-8
script:
- mvn -B clean install -s settings.xml
#- cat report/target/coverage-report/html/index.html
except:
- master
# masterJobWindows:
# stage: windows
# script:
# - mvn -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn -B clean install --settings settings.xml
# - cat report/target/coverage-report/html/index.html
# except:
# - mvn clean deploy -s settings.xml
# - mvn package sonar:sonar -s settings.xml
# tags:
# - Windows10_OS
# only:
# - master
# branchJobWindows:
# stage: windows
# script:
# - mvn -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn -B clean install --settings settings.xml
# tags:
# - Windows10_OS
# except:
# - master
#IntegrateionTest:
# tags:
......
# (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"
......
# 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)
This repository includes the classes for the management of the simulation, the physics computations, the environment, the sensors and the vehicles.
## >> [Link to the Documentation for this project (Wiki)](https://git.rwth-aachen.de/monticore/EmbeddedMontiArc/simulators/simulation/-/wikis/home) <<
Discrete time steps are used to advance the simulation.
## Usage
The environment is created by parsing OpenStreetMap data.
To use the different sub-project as maven dependency, add the following to your pom's `<dependencies>`:
# Vehicle Dynamics Model
```xml
<dependency>
<groupId>montisim</groupId>
<artifactId>*sub-project*</artifactId>
<version>${revision}</version>
</dependency>
```
A vehicle dynamics model is used to calculate the physical behaviour for a car in the simulation. This vehicle dynamics model is modeled in Modelica and then compiled into functional mock-up units. These units are then accessed and used in the `VehicleDynamicsModel` class.
`*sub-project*` can be any of the following:
To compile updated Modelica models into functional mock-up units, the _.mo_ files (the models) have to be exported via FMI into a _.fmu_ file using the OpenModelica Connection Editor v.1.12.0 (64-bit).
__NOTE:__ When new fmu's are added to the simulation, the _deployment.bat_ that copies the fmu's into the SmartFoxServer has to be updated as well.
The settings are:
* Version: 2.0
* Type: Co-Simulation
* Platform: Static
# Simulation Debugging and Debug Plotter
To quickly debug the simulator, a simulation can be configured and executed without starting up the server. An example is given in the `firstTest()` jUnit test in the `SimulatieVehicleTest` test class.
The debug plotter can be used to visualize a simulation that contains only __one__ physical vehicle. A use case for the debug plotter is also given in `firstTest()`. The plotter is registered to the simulation as an observer and is then generating one visualisation chart for each loop iteration.
# Height data
Height data is read from SRTM files, which are documented [here](https://dds.cr.usgs.gov/srtm/version2_1/Documentation/SRTM_Topo.pdf). Additional height data files can be downloaded from [this source](https://dds.cr.usgs.gov/srtm/version2_1/SRTM3/), where you need to select the continent and then search for the file you need. The file name format is dependent on latitude/longitude and defined as `[N/S][<LAT>][O/W][<LONG>].hgt`.
Each file contains data until the next higher latitude/longitude. For example file N50E006.hgt will cover all pairs of (latitude,longitude) from (50,6) to (51,7) (with resolution 3/3600=0.000833).
To determine min/max latitude/longitude, the file names of all loaded height data files need to be parsed according to the described format and then compared to find the lowest/highest values. Let's say N50E006.hgt and N51E006.hgt are loaded, then you would get minLat=50, minLong=6, maxLat=52, maxLong=7.
- `environment`
- `eesimulator`
- `vehicle`
- `eecomponents`
- `simulator`
(c) https://github.com/MontiCore/monticore
The license generally applicable for this project
can be found under https://github.com/MontiCore/monticore.
\ No newline at end of file
/**
* (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 java.time.Instant;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import de.rwth.monticore.EmbeddedMontiArc.simulators.commons.controller.commons.BusEntry;
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;
private final EEComponentType componentType;
private final UUID Id;
public AbstractEEComponent(EESimulator simulator, EEComponentType type) {
if (simulator == null || type == null) {
throw new NullArgumentException();
}
this.simulator = simulator;
this.componentType = type;
this.Id = UUID.randomUUID();
}
@Override
public EEComponentType getComponentType() {
return componentType;
}
@Override
public EESimulator getSimulator() {
return simulator;
}
@Override
public UUID getId() {
return Id;
}
/**
* Send message to all targets that are registered for this message in targetsByMessageId
* @param message message to be send
* @param messageLen length of message in bytes
* @param messageId message id of the message
* @param eventTime time when the message is sent
*/
@Override
public void sendMessage(Object message, int messageLen , BusEntry messageId, Instant eventTime) {
List<EEComponent> targets = this.getTargetsByMessageId().getOrDefault(messageId, Collections.emptyList());
for(EEComponent target : targets) {
BusMessage msg = new BusMessage(message, 6, messageId,
eventTime, this.getId(), target);
this.getSimulator().addEvent(msg);
}
}
}
/**
* (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 de.rwth.monticore.EmbeddedMontiArc.simulators.commons.controller.commons.BusEntry;
import simulation.bus.Bus;
import simulation.bus.BusMessage;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
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{
/**
* 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);
}
@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());
}
}
/**
* 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 Pair<Bus, Bus> getConnectedBuses() {
return this.connected;
}
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);
}
}
/**
* (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 de.rwth.monticore.EmbeddedMontiArc.simulators.commons.controller.commons.BusEntry;
import de.rwth.monticore.EmbeddedMontiArc.simulators.hardware_emulator.interfaces.*;
import de.rwth.monticore.EmbeddedMontiArc.simulators.hardware_emulator.config.ControllerConfig;
import org.apache.commons.math3.linear.RealVector;
import simulation.bus.Bus;
import simulation.bus.BusMessage;
import java.io.Serializable;
import java.time.Duration;
import java.time.Instant;
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 ControllerAsEEComponent 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);
add(BusEntry.SENSOR_COMPASS);
add(BusEntry.ACTUATOR_ENGINE_CURRENT);
add(BusEntry.ACTUATOR_BRAKE_CURRENT);
add(BusEntry.ACTUATOR_STEERING_CURRENT);
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
*/
SoftwareSimulator softwareSimulator;
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();
/**
* Time when the controller was executed last
*/
Instant lastFinishTime = Instant.EPOCH;
/**
* Create a ControllerAsEEComponent that is connected to bus.
* @param bus Bus that the ControllerAsEEComponent is connected to
* @return ControllerAsEEComponent with default configuration
*/
public static ControllerAsEEComponent createControllerAsEEComponent(Bus bus) {
return createControllerAsEEComponent(Collections.singletonList(bus));
}
/**
* Create a ControllerAsEEComponent that is connected to bus.
* @param buses Buses that the ControllerAsEEComponent is connected to
* @return ControllerAsEEComponent with default configuration
*/
public static ControllerAsEEComponent createControllerAsEEComponent(List<Bus> buses){
HashMap<BusEntry, List<EEComponent>> targetsByMessageId = new HashMap<>();
targetsByMessageId.put(BusEntry.ACTUATOR_BRAKE, new LinkedList<>());
targetsByMessageId.put(BusEntry.ACTUATOR_STEERING, new LinkedList<>());
targetsByMessageId.put(BusEntry.ACTUATOR_ENGINE, new LinkedList<>());
for (Bus bus : buses) {
if (bus.subscribedMessages.contains(BusEntry.ACTUATOR_ENGINE)) {
targetsByMessageId.get(BusEntry.ACTUATOR_ENGINE).add(bus);
}
if (bus.subscribedMessages.contains(BusEntry.ACTUATOR_STEERING)) {
targetsByMessageId.get(BusEntry.ACTUATOR_STEERING).add(bus);
}
if (bus.subscribedMessages.contains(BusEntry.ACTUATOR_BRAKE)) {
targetsByMessageId.get(BusEntry.ACTUATOR_BRAKE).add(bus);
}
}
return new ControllerAsEEComponent(buses.get(0).getSimulator(), targetsByMessageId);
}
public ControllerAsEEComponent(EESimulator simulator, HashMap<BusEntry, List<EEComponent>> targetsByMessageId) {
super(simulator, EEComponentType.AUTOPILOT, STANDARD_SUBSCRIBED_MESSAGES, targetsByMessageId);
}
public void setCycleTime(Duration cycleTime) {
this.cycleTime = cycleTime;
}
public Duration getCycleTime() {
return cycleTime;
}