Commit db8306ed authored by Julian Zobel's avatar Julian Zobel
Browse files

Merge branch 'jz/bachelor-thesis-louis-neumann' into jz/master

parents a886bf18 bcf79843
......@@ -31,6 +31,8 @@ package de.tud.kom.p2psim.api.energy;
*/
public interface Battery extends Cloneable {
public static double uJconverison = 1000000;
/**
* Returns the maximum energy level in uJ.
*
......
......@@ -37,6 +37,9 @@ import de.tudarmstadt.maki.simonstrator.api.component.network.NetworkComponent.N
*
* @author Bjoern Richerzhagen
* @version 1.0, 25.02.2012
*
* @changes:
* Louis Neumann - setting LORA to "unlimited" bandwith
*/
public enum PhyType {
......@@ -92,7 +95,7 @@ public enum PhyType {
* Assuming the following defaults: zero link-layer packet loss, 0.3 kbit/s BW,
* 500us latency, 1kByte MTU
*/
LORA(NetInterfaceName.LORA, 0, 1 * Rate.kbit_s,
LORA(NetInterfaceName.LORA, 0, 1 * Rate.Gbit_s,
500 * Time.MICROSECOND, 1024, true);
......
......@@ -48,9 +48,19 @@ public interface ControllableLocationActuator extends Actuator {
public boolean deactivate();
public PositionVector getCurrentLocation();
public PositionVector getCurrentDirection();
public PositionVector getBaseLocation();
public void updateCurrentDirection(PositionVector direction);
public double getCurrentBatteryLevel();
public double getCurrentBatteryEnergy();
public double getMaximumBatteryCapacity();
public LinkedList<PositionVector> getTargetLocations();
public void setTargetLocation(PositionVector targetLocation, ReachedLocationCallback cb);
......@@ -76,4 +86,6 @@ public interface ControllableLocationActuator extends Actuator {
public double getMaxMovementSpeed();
public double getMovementSpeed();
public double estimatePowerConsumption(double velocity);
}
......@@ -21,12 +21,13 @@
package de.tud.kom.p2psim.api.topology.movement;
import de.tud.kom.p2psim.api.topology.component.ControllableLocationActuator;
import de.tud.kom.p2psim.impl.energy.components.ActuatorEnergyComponent;
import de.tud.kom.p2psim.impl.energy.components.StateActuatorEnergyComponent;
import de.tud.kom.p2psim.impl.energy.components.StatelessMotorComponent;
public interface SimUAVLocationActuator extends SimLocationActuator, ControllableLocationActuator {
public UAVMovementModel getUAVMovement();
public void setUAVMovement(UAVMovementModel uavMovement);
public ActuatorEnergyComponent getActuatorEnergyComponent();
}
......@@ -21,16 +21,23 @@
package de.tud.kom.p2psim.api.topology.movement;
import java.util.LinkedList;
import de.tud.kom.p2psim.impl.energy.components.StatelessMotorComponent;
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
import de.tudarmstadt.maki.simonstrator.api.uavsupport.callbacks.ReachedLocationCallback;
public interface UAVMovementModel {
public void setPreferredCruiseSpeed(double v_pref);
public void setMotorControl(StatelessMotorComponent motor);
public void setPreferredSpeed(double v_pref);
public double getMaxCruiseSpeed();
public double getMinCruiseSpeed();
public double verticalAscentMaxVelocity();
public double horizontalMaxVelocity();
public double getCurrentSpeed();
public double minimumVelocity();
public double estimatePowerConsumption(double velocity);
public void move(long timeBetweenMovementOperations);
......
......@@ -114,8 +114,17 @@ public class MaxPeerCountChurnGenerator
@XMLConfigurableConstructor({ "file", "maxNumberOfNodes" })
public MaxPeerCountChurnGenerator(String file, int maxNumberOfNodes) {
this.maxNumberOfNodes = maxNumberOfNodes;
parseTrace(file);
parseTrace(file);
}
@XMLConfigurableConstructor({ "churnStart", "maxNumberOfNodes", "burstLength" })
public MaxPeerCountChurnGenerator(long churnStart, int maxNumberOfNodes, long burstLength) {
this.maxNumberOfNodes = maxNumberOfNodes;
churnInfos.add(new ChurnInfo(churnStart, burstLength, maxNumberOfNodes));
this.setChurnStart(churnStart);
}
/**
* A class that implements the {@link LifecycleComponent}-interface and can
......
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* PeerfactSim.KOM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.energy.components;
import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor;
public class MotorCharacteristic {
private final double thrust;
private final double current;
@XMLConfigurableConstructor({ "thrust", "current" })
public MotorCharacteristic(double thrust, double current) {
this.thrust = thrust;
this.current = current;
}
public double getCurrent() {
return current;
}
public double getThrust() {
return thrust;
}
@Override
public String toString() {
return "["+ thrust + "N @ " + current + "A]";
}
}
......@@ -36,7 +36,7 @@ import de.tudarmstadt.maki.simonstrator.api.Time;
* @author Julian Zobel
* @version 1.0, 11.09.2018
*/
public class ActuatorEnergyComponent implements EnergyComponent {
public class StateActuatorEnergyComponent implements EnergyComponent {
/**
* States supported by this energy component
......@@ -53,7 +53,7 @@ public class ActuatorEnergyComponent implements EnergyComponent {
private double actuatorLoad;
public ActuatorEnergyComponent(int numberOfActuators, double volt, double hoverAmp, double maxAmp) {
public StateActuatorEnergyComponent(int numberOfActuators, double volt, double hoverAmp, double maxAmp) {
OFF = new DefaultEnergyState("OFF", 0);
FLY = new DefaultEnergyState("FLY", numberOfActuators * (hoverAmp * volt) * 1000000);
MAX = new DefaultEnergyState("MAX", numberOfActuators * (maxAmp * volt) * 1000000);
......
/*
* Copyright (c) 2005-2010 KOM � Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* PeerfactSim.KOM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.energy.components;
import java.util.Comparator;
import java.util.LinkedList;
import de.tud.kom.p2psim.api.energy.ComponentType;
import de.tud.kom.p2psim.api.energy.EnergyComponent;
import de.tud.kom.p2psim.api.energy.EnergyEventListener;
import de.tud.kom.p2psim.api.energy.EnergyState;
import de.tud.kom.p2psim.impl.energy.DefaultEnergyState;
import de.tudarmstadt.maki.simonstrator.api.Time;
/**
* Component for devices that provide thrust, such as electrical motors for UAV propulsion.
* Is configured by {@link MotorCharacteristic}s with a given thrust (N) and a given current (A).
* Values in between given characteristics are calculated by linear interpolation.
*
*
* @author Julian Zobel
* @version 1.0, 05.03.2019
*/
public class StatelessMotorComponent implements EnergyComponent {
public enum componentState {OFF, ON}
private componentState state;
private EnergyEventListener energyModel;
private long lastEnergyConsumationTime;
private double volts;
private final double uJconversionFactor = 1000000;
private final int numberOfActuators;
private double thrust;
private double amps;
private EnergyState energyState;
private LinkedList<MotorCharacteristic> characteristics = new LinkedList<>();
public StatelessMotorComponent(int numberOfActuators, double volt) {
this.volts = volt;
this.numberOfActuators = numberOfActuators;
this.state = componentState.OFF;
this.lastEnergyConsumationTime = Time.getCurrentTime();
thrust = 0;
amps = 0;
energyState = new DefaultEnergyState("OFF", 0);
}
/**
* Get the maximum thrust provided by this component.
* @return
*/
public double getMaxThrust() {
return characteristics.getLast().getThrust() * numberOfActuators;
}
/**
* Set the new energy state and calculate the energy consumption from the last state
*/
private void setEnergyState() {
// set the new energy state
EnergyState newState;
if(state == componentState.ON) {
newState = new DefaultEnergyState("Actuator", numberOfActuators * (amps * volts) * uJconversionFactor);
}
else {
newState = new DefaultEnergyState("OFF", 0);
}
// calculate energy consumption for the previous state
long timeSpentInState = Time.getCurrentTime() - lastEnergyConsumationTime;
double cons = calculateEnergyConsumation(energyState, timeSpentInState);
energyModel.componentConsumedEnergy(this, cons);
// set new state
energyState = newState;
lastEnergyConsumationTime = Time.getCurrentTime();
}
/**
* Request a given amount of thrust to be provided from this component. If the amount is less than the minimum
* or more than the maximum, the minimum or maximum thrust values, respectively, are enforced.
*
* @param targetThrust
* @return The amount of thrust this component now generates.
*/
public double requestThrust(double targetThrust) {
if(targetThrust == 0 || targetThrust <= numberOfActuators * characteristics.getFirst().getThrust()) {
setLoad(characteristics.getFirst());
}
else if(targetThrust >= numberOfActuators * characteristics.getLast().getThrust()) {
setLoad(characteristics.getLast());
}
else {
calculateAndSetThrustRelatedAmpereDraw(targetThrust);
}
return this.thrust;
}
/**
*
* @param targetThrust
* @return The power consumption for the target thrust in uW (micro watt)
*/
public double estimatePowerConsumptionWatt(double targetThrust) {
if(targetThrust == 0 || targetThrust <= numberOfActuators * characteristics.getFirst().getThrust()) {
// not allowed
return Double.NaN;
}
else if(targetThrust > numberOfActuators * characteristics.getLast().getThrust()) {
// not allowed
return Double.NaN;
}
else {
double amps = approximateAmpereDraw(targetThrust);
return numberOfActuators * amps * volts;
}
}
/**
* Given an amount of thrust between the minimum and maximum values, the required current
* to provide this amount of thrust is calculated by linear interpolation by the nearest lower
* and upper {@link MotorCharacteristic}s.
*
* @param targetThrust
* @return the approximated ampere draw
*/
private double approximateAmpereDraw(double targetThrust) {
MotorCharacteristic lower = null, upper = null;
// find the lower and upper bounding characteristics
for (MotorCharacteristic ch : characteristics) {
//
if(ch.getThrust() * numberOfActuators == targetThrust) {
return ch.getCurrent();
}
else {
// list is sorted, lower bound is the biggest that is lower
if(ch.getThrust() * numberOfActuators < targetThrust) {
lower = ch;
}
// the first that is greater is used as upper bound
else if(ch.getThrust() * numberOfActuators > targetThrust) {
upper = ch;
break;
}
}
}
if(upper == null || lower == null) {
throw new UnsupportedOperationException("Lower or upper bounds cannot be null");
}
if(upper.getThrust() * numberOfActuators < targetThrust || lower.getThrust() * numberOfActuators > targetThrust) {
throw new UnsupportedOperationException("Lower or upper bound do not match");
}
/*
* Calculate the approximated current with the upper and lower bounds:
* Amp_approx = Amp_lower + (T_target - T_lower)/(T_upper - T_lower) * (Amp_upper - Amp_lower)
*/
double delta = (targetThrust - (lower.getThrust() * numberOfActuators))/(numberOfActuators * (upper.getThrust() - lower.getThrust()));
return lower.getCurrent() + delta * (upper.getCurrent() - lower.getCurrent());
}
/**
* Approximates the ampere draw required forthe requested thrust
*
* Target thrust should be strictly within the possible thrust limits
*
*/
private void calculateAndSetThrustRelatedAmpereDraw(double targetThrust) {
double calculatedAmps = approximateAmpereDraw(targetThrust);
setLoad(targetThrust, calculatedAmps);
}
private void setLoad(double thrust, double amps) {
this.thrust = thrust;
this.amps = amps;
setEnergyState();
}
private void setLoad(MotorCharacteristic ch) {
this.thrust = ch.getThrust();
this.amps = ch.getCurrent();
setEnergyState();
}
/**
* Add a {@link MotorCharacteristic} for this motor.
*
* @param c
*/
public void addChar(MotorCharacteristic c) {
characteristics.add(c);
// sort the characteristics starting from low to high thrust
characteristics.sort(new Comparator<MotorCharacteristic>() {
@Override
public int compare(MotorCharacteristic o1,
MotorCharacteristic o2) {
return (int) (o1.getThrust() - o2.getThrust());
}
});
}
@Override
public void eventOccurred(Object content, int type) {
// TODO Auto-generated method stub
}
@Override
public ComponentType getType() {
return ComponentType.ACTUATOR;
}
@Override
public boolean turnOff() {
this.thrust = 0;
this.amps = 0;
this.state = componentState.OFF;
setEnergyState();
return true;
}
@Override
public boolean turnOn() {
if (isAvailable()) {
if(this.state != componentState.ON) {
this.state = componentState.ON;
requestThrust(0);
}
return true;
}
return false;
}
public boolean isAvailable() {
if (energyModel.componentCanBeActivated(this)) {
return true;
}
return false;
}
@Override
public boolean isOn() {
if(this.state != componentState.OFF && isAvailable()) {
return true;
}
return false;
}
@Override
public void setEnergyEventListener(EnergyEventListener listener) {
energyModel = listener;
}
public EnergyState getCurrentState() {
return energyState;
}
}
/*
* Copyright (c) 2005-2010 KOM � Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* PeerfactSim.KOM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.energy.configs;
import java.util.LinkedList;
import de.tud.kom.p2psim.api.common.SimHost;
import de.tud.kom.p2psim.api.energy.EnergyConfiguration;
import de.tud.kom.p2psim.impl.energy.components.MotorCharacteristic;
import de.tud.kom.p2psim.impl.energy.components.StatelessMotorComponent;
/**
*
*
* @author Julian Zobel
* @version 1.0, 05.03.2019
*/
public class ActuatorConfiguration implements EnergyConfiguration<StatelessMotorComponent> {
private int numberOfActuators;
private double volt;
private LinkedList<MotorCharacteristic> characteristics = new LinkedList<>();
@Override
public StatelessMotorComponent getConfiguredEnergyComponent(SimHost host) {
StatelessMotorComponent comp = new StatelessMotorComponent(numberOfActuators, volt);
for (MotorCharacteristic c : characteristics) {
comp.addChar(c);
}
return comp;
}
@Override
public String getHelp() {
return "Fix actuator energy consumption config";
}
@Override
public boolean isWellConfigured() {
if(numberOfActuators >= 1 && volt > 0 && characteristics.size() >= 2) {
return true;
}
return false;
}
public void setNumberOfActuators(int num) {
numberOfActuators = num;
}
public void setVolt(double voltage) {
this.volt = voltage;
}
public void setMotorCharacteristic(MotorCharacteristic c) {
characteristics.add(c);
}
}
......@@ -22,15 +22,15 @@ package de.tud.kom.p2psim.impl.energy.configs;
import de.tud.kom.p2psim.api.common.SimHost;
import de.tud.kom.p2psim.api.energy.EnergyConfiguration;
import de.tud.kom.p2psim.impl.energy.components.ActuatorEnergyComponent;
import de.tud.kom.p2psim.impl.energy.components.StateActuatorEnergyComponent;
/**
* Energy Configuration for {@link ActuatorEnergyComponent}s.
* Energy Configuration for {@link StateActuatorEnergyComponent}s.
*
* @author Julian Zobel
* @version 1.0, 11.09.2018
*/
public class ActuatorEnergyConsumptionConfig implements EnergyConfiguration<ActuatorEnergyComponent> {
public class ActuatorEnergyConsumptionConfig implements EnergyConfiguration<StateActuatorEnergyComponent> {
private int numberOfActuators;
private double volt;
......@@ -38,8 +38,8 @@ public class ActuatorEnergyConsumptionConfig implements EnergyConfiguration<Actu
private double flyAmp; // in ampere
@Override
public ActuatorEnergyComponent getConfiguredEnergyComponent(SimHost host) {
return new ActuatorEnergyComponent(numberOfActuators, volt, hoverAmp, flyAmp);
public StateActuatorEnergyComponent getConfiguredEnergyComponent(SimHost host) {
return new StateActuatorEnergyComponent(numberOfActuators, volt, hoverAmp, flyAmp);
}
@Override
......
......@@ -25,7 +25,7 @@ import de.tud.kom.p2psim.api.energy.Battery;
import de.tud.kom.p2psim.api.energy.EnergyComponent;
import de.tud.kom.p2psim.api.energy.EnergyEventListener;
import de.tud.kom.p2psim.api.network.SimNetInterface;
import de.tud.kom.p2psim.impl.energy.components.ActuatorEnergyComponent;
import de.tud.kom.p2psim.impl.energy.components.StateActuatorEnergyComponent;
/**
* Energy Model based on multiple exchangeable components. Each component states the amount of consumed energy,
......@@ -60,8 +60,8 @@ public class ComponentBasedEnergyModel extends AbstractEnergyModel implements En
monitorEmptyBattery();
if(component instanceof ActuatorEnergyComponent) {
((ActuatorEnergyComponent) component).turnOff();
if(component instanceof StateActuatorEnergyComponent) {
((StateActuatorEnergyComponent) component).turnOff();
}
/*
......
......@@ -208,7 +208,7 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
/* Real World Starting Time:
* Block till we're allowed to start.
*/
if( realWorldStartTime != null ) {
if(realWorldStartTime != null ) {
try {
......@@ -234,9 +234,13 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
finishedWithoutError = true;
} catch (RuntimeException e) {
finishedWithoutError = false;
finishedWithoutError = false;
reason = e;
throw e;
} finally {
this.running = false;
// After a simulation start the mechanisms, which
// finalize a simulation
......@@ -248,10 +252,18 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
this.running = false;
if (finishedWithoutError) {
Monitor.log(Simulator.class, Level.INFO,
"Simulation successfully finished...");
"Simulation successfully finished :)");
} else {
if(reason == null) {
Monitor.log(Simulator.class, Level.ERROR,
"Simulation finished with unresolved errors ???");
}
else {
Monitor.log(Simulator.class, Level.ERROR,
"Simulation finished with errors...\n" + reason);
"Simulation finished with errors :( \n " +
reason.toString() + " : " + reason.getStackTrace());
}
}
long runTime = System.currentTimeMillis() - startTime;
long minutes = (long) Math.floor((runTime) / 60000);
......
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* PeerfactSim.KOM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.topology.component;
import de.tudarmstadt.maki.simonstrator.api.component.core.MonitorComponent.Analyzer;
public interface UAVStatisticAnalyzer extends Analyzer {
public void uavSwitchedStates(UAVTopologyComponent uav, UAVTopologyComponent.UAVstate newState);
}
......@@ -22,9 +22,6 @@ package de.tud.kom.p2psim.impl.topology.component;
import java.util.LinkedList;
import java.util.Set;
import org.apache.batik.bridge.AbstractSVGGradientElementBridge.Stop;
import de.tud.kom.p2psim.api.common.SimHost;
import de.tud.kom.p2psim.api.energy.ComponentType;
import de.tud.kom.p2psim.api.energy.EnergyModel;
......@@ -35,15 +32,15 @@ import de.tud.kom.p2psim.api.topology.movement.SimUAVLocationActuator;
import de.tud.kom.p2psim.api.topology.movement.UAVMovementModel;
import de.tud.kom.p2psim.api.topology.placement.PlacementModel;
import de.tud.kom.p2psim.impl.energy.RechargeableBattery;
import de.tud.kom.p2psim.impl.energy.components.ActuatorEnergyComponent;
import de.tud.kom.p2psim.impl.energy.components.StatelessMotorComponent;
import de.tud.kom.p2psim.impl.energy.models.AbstractEnergyModel;
import de.tud.kom.p2psim.impl.topology.placement.UAVBasePlacement;
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
import de.tudarmstadt.maki.simonstrator.api.Monitor;
import de.tudarmstadt.maki.simonstrator.api.component.ComponentNotAvailableException;
import de.tudarmstadt.maki.simonstrator.api.component.overlay.OverlayComponent;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location;
import de.tudarmstadt.maki.simonstrator.api.uavsupport.callbacks.BaseConnectedCallback;
import de.tudarmstadt.maki.simonstrator.api.uavsupport.callbacks.BaseDisconnectedCallback;
import de.tudarmstadt.maki.simonstrator.api.uavsupport.callbacks.BatteryReplacementCallback;
......@@ -64,7 +61,9 @@ public class UAVTopologyComponent extends AbstractTopologyComponent implements S
private OverlayComponent uavOverlayComponent;
private ActuatorEnergyComponent actuator;
protected PositionVector direction;
private StatelessMotorComponent actuator;
private RechargeableBattery battery;
private UAVstate state = UAVstate.OFFLINE;
......@@ -82,6 +81,7 @@ public class UAVTopologyComponent extends AbstractTopologyComponent implements S
public UAVTopologyComponent(SimHost host, Topology topology,
MovementModel movementModel, PlacementModel placementModel, boolean registerAsInformationProviderInSiS) {
super(host, topology, movementModel, placementModel, registerAsInformationProviderInSiS);
direction = new PositionVector(0,-1,0);
}
@Override
......@@ -90,7 +90,8 @@ public class UAVTopologyComponent extends AbstractTopologyComponent implements S
try {
actuator = getHost().getComponent(EnergyModel.class)
.getComponent(ComponentType.ACTUATOR, ActuatorEnergyComponent.class);
.getComponent(ComponentType.ACTUATOR, StatelessMotorComponent.class);
movement.setMotorControl(actuator);
} catch (ComponentNotAvailableException e) {
System.err.println("No Acutator Energy Component was found!");
}
......@@ -108,6 +109,11 @@ public class UAVTopologyComponent extends AbstractTopologyComponent implements S
public void setState(UAVstate newState) {
this.state = newState;
// TODO analyzer
if(Monitor.hasAnalyzer(UAVStatisticAnalyzer.class)) {
Monitor.getOrNull(UAVStatisticAnalyzer.class).uavSwitchedStates(this, newState);
}
}
public void setUAVComponent(OverlayComponent uavOverlayComponent) {
......@@ -120,12 +126,12 @@ public class UAVTopologyComponent extends AbstractTopologyComponent implements S
@Override
public double getMinMovementSpeed() {
return movement.getMinCruiseSpeed();
return movement.minimumVelocity();
}
@Override
public double getMaxMovementSpeed() {
return movement.getMaxCruiseSpeed();
return movement.horizontalMaxVelocity();
}
@Override
......@@ -135,14 +141,14 @@ public class UAVTopologyComponent extends AbstractTopologyComponent implements S
@Override
public void setMovementSpeed(double speed) {
movement.setPreferredCruiseSpeed(speed);
movement.setPreferredSpeed(speed);
}
@Override
public boolean isActive() {
if(actuator.isOn())
if(actuator.isOn()) {
return true;
else {
} else {
if(state == UAVstate.ACTION || state == UAVstate.RETURN) {
this.deactivate();
}
......@@ -153,7 +159,7 @@ public class UAVTopologyComponent extends AbstractTopologyComponent implements S
@Override
public boolean activate() {
if(actuator.turnOn()) {
state = UAVstate.ACTION;
this.setState(UAVstate.ACTION);
return true;
}
else {
......@@ -165,18 +171,15 @@ public class UAVTopologyComponent extends AbstractTopologyComponent implements S
public boolean deactivate() {
actuator.turnOff();
if(this.position.getAltitude() != 0) {
state = UAVstate.CRASHED;
System.err.println("UAV was destroyed due to actuator deactivation during flight");
if(this.position.getAltitude() != 0) {
this.setState(UAVstate.CRASHED);
uavOverlayComponent.shutdown();
shutdownCommunication();
}
else {
state = UAVstate.OFFLINE;
}
} else {
this.setState(UAVstate.OFFLINE);
}
return true;
}
......@@ -190,6 +193,11 @@ public class UAVTopologyComponent extends AbstractTopologyComponent implements S
public double getCurrentBatteryLevel() {
return battery.getCurrentPercentage();
}
@Override
public double getCurrentBatteryEnergy() {
return battery.getCurrentEnergyLevel();
}
public RechargeableBattery getBattery() {
return battery;
......@@ -205,11 +213,6 @@ public class UAVTopologyComponent extends AbstractTopologyComponent implements S
this.movement = uavMovement;
}
@Override
public ActuatorEnergyComponent getActuatorEnergyComponent() {
return actuator;
}
@Override
public Set<AttractionPoint> getAllAttractionPoints() {
throw new UnsupportedOperationException();
......@@ -262,8 +265,8 @@ public class UAVTopologyComponent extends AbstractTopologyComponent implements S
}
@Override
public void returnToBase(ReachedLocationCallback cb) {
this.state = UAVstate.RETURN;
public void returnToBase(ReachedLocationCallback cb) {
this.setState(UAVstate.RETURN);
ReachedLocationCallback returnCallback = new ReachedLocationCallback() {
......@@ -274,13 +277,15 @@ public class UAVTopologyComponent extends AbstractTopologyComponent implements S
}
};
movement.setPreferredSpeed(movement.horizontalMaxVelocity());
movement.setTargetLocation(baseLocation, returnCallback);
}
public void batteryReplacement(BatteryReplacementCallback cb) {
if(state != UAVstate.BASE_CONNECTION)
if(state != UAVstate.BASE_CONNECTION) {
throw new UnsupportedOperationException("Cannot recharge if not connected to base!");
}
BaseTopologyComponent base = UAVBasePlacement.base;
base.getCharger().charge(this, cb);
......@@ -298,8 +303,7 @@ public class UAVTopologyComponent extends AbstractTopologyComponent implements S
if(cb != null)
cb.successfulConnection();
this.state = UAVstate.BASE_CONNECTION;
this.setState(UAVstate.BASE_CONNECTION);
shutdownCommunication();
}
......@@ -313,7 +317,6 @@ public class UAVTopologyComponent extends AbstractTopologyComponent implements S
if(cb != null)
cb.successfulDisconnection();
this.state = UAVstate.OFFLINE;
}
private void shutdownCommunication() {
......@@ -326,4 +329,31 @@ public class UAVTopologyComponent extends AbstractTopologyComponent implements S
net.goOnline();
}
@Override
public PositionVector getCurrentDirection() {
return direction;
}
@Override
public void updateCurrentDirection(PositionVector direction) {
this.direction.set(direction);
}
@Override
public double getMaximumBatteryCapacity() {
return battery.getMaximumEnergyLevel();
}
@Override
public double estimatePowerConsumption(double velocity) {
return movement.estimatePowerConsumption(velocity);
}
@Override
public PositionVector getBaseLocation() {
return baseLocation.clone();
}
}
......@@ -20,110 +20,235 @@
package de.tud.kom.p2psim.impl.topology.movement.aerial;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
import org.joda.time.tz.ZoneInfoProvider;
import org.apache.commons.math3.geometry.Vector;
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
import org.apache.commons.math3.geometry.euclidean.twod.Vector2D;
import de.tud.kom.p2psim.api.topology.movement.UAVMovementModel;
import de.tud.kom.p2psim.impl.energy.components.StatelessMotorComponent;
import de.tud.kom.p2psim.impl.topology.component.UAVTopologyComponent;
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
import de.tudarmstadt.maki.simonstrator.api.Time;
import de.tudarmstadt.maki.simonstrator.api.uavsupport.callbacks.ReachedLocationCallback;
/**
* Local movement logic specifically designs the movement for multicopter UAVs.
* This simple movement logic uses straight forward movement with the maximum speed available.
*
* @author Julian Zobel
* @version 1.0, 11.09.2018
*/
public class SimpleMutlicopterMovement implements UAVMovementModel {
public class MulticopterMovement implements UAVMovementModel {
private UAVTopologyComponent topologyComponent;
private final double maxCruiseSpeed;
private final double minCruiseSpeed;
private double preferredCruiseSpeed;
private PositionVector direction;
private double currentAngleOfAttack;
private double currentSpeed;
private double preferredSpeed;
private LinkedList<PositionVector> route = new LinkedList<>();
private Map<PositionVector, ReachedLocationCallback> locationCallbacks = new LinkedHashMap<>(); // TODO callback interface
private StatelessMotorComponent motor;
public SimpleMutlicopterMovement(UAVTopologyComponent topologyComponent, double maxCruiseSpeed, double minCruiseSpeed) {
private double mass = 1.465; // kg
private final double airdensity = 1.2255; // kg/m^3
private final double gravity = 9.807; // m/s^2
private double A_top = 0.245; // m^2
private double A_front = 0.04; // m^2
private double dragCoefficient = 0.5;
private double maxPitchAngle = Math.toRadians(45); // 45° max angle
private double descentVelocityMax = 5; // m/s
private double maxTurnAngle = Math.toRadians(90); // 90° per second turn angle
public MulticopterMovement(UAVTopologyComponent topologyComponent) {
this.topologyComponent = topologyComponent;
this.maxCruiseSpeed = maxCruiseSpeed;
this.minCruiseSpeed = minCruiseSpeed;
this.preferredCruiseSpeed = this.maxCruiseSpeed;
this.direction = new PositionVector(0,0);
}
/*
*
*/
public double verticalDescentMaxThrust() {
// m * g - 0.5 * p * C * A * v^2
return hoverThrustRequired() - 0.5 * bodyDrag(0, new PositionVector(0,0,1)) * descentVelocityMax * descentVelocityMax;
}
public double verticalAscentMaxAcceleration() {
return (motor.getMaxThrust() - hoverThrustRequired()) / mass;
}
public double verticalAscentMaxVelocity() {
double maxThrust = motor.getMaxThrust();
return Math.sqrt(2.0 * (maxThrust - hoverThrustRequired()) / bodyDrag(0, new PositionVector(0,0,1)));
}
public double hoverThrustRequired() {
return mass * gravity;
}
public double horizontalMaxVelocity() {
@Override
public void setPreferredCruiseSpeed(double v_pref) {
this.preferredCruiseSpeed = v_pref;
double horizontalThrust = horizontalMaxThrust();
double maxVelocity = Math.sqrt( (2.0 * horizontalThrust) / bodyDrag(maxPitchAngle, new PositionVector(1,0,0)));
return maxVelocity;
}
@Override
public double getMaxCruiseSpeed() {
return maxCruiseSpeed;
public double horizontalMaxThrust() {
// hoverthrust / cos => amount of thrust in horizonal direction with °angle
double stableAltitudeMaximumTotalThrust = hoverThrustRequired() / Math.cos(maxPitchAngle);
// fraction of total thrust in horizonal (forward) direction with °angle
double maximumHorizontalThrustStableAltitude = stableAltitudeMaximumTotalThrust * Math.sin(maxPitchAngle);
return maximumHorizontalThrustStableAltitude;
}
@Override
public double getMinCruiseSpeed() {
return minCruiseSpeed;
public double bodyDrag(double angleRadians, PositionVector direction) {
return airdensity * dragCoefficient * areaExposedToDrag(angleRadians, direction);
}
@Override
public double getCurrentSpeed() {
return currentSpeed;
public double areaExposedToDrag(double angleRadians, PositionVector direction) {
Vector2D v = new Vector2D(Math.abs(direction.getX()) + Math.abs(direction.getY()), Math.abs(direction.getZ()));
v = v.normalize();
double areaExposedFront = v.getX() * (Math.sin(angleRadians) * A_top + Math.cos(angleRadians) * A_front);
double areaExposedTop = v.getY() * (Math.cos(angleRadians) * A_top + Math.sin(angleRadians) * A_front);
return areaExposedFront + areaExposedTop;
}
/*
* F_drag [N] = 0.5 * p * C_drag * A * v^2
*/
public double currentDrag() {
return 0.5 * bodyDrag(currentAngleOfAttack, direction) * currentSpeed * currentSpeed;
}
/*
*
*/
@Override
public void setMotorControl(StatelessMotorComponent motor) {
this.motor = motor;
}
@Override
public void move(long timeBetweenMovementOperations) {
if(topologyComponent.isActive() && !route.isEmpty()) {
PositionVector currentPosition= topologyComponent.getRealPosition();
if(motor.isOn() && !route.isEmpty()) {
PositionVector position = new PositionVector(topologyComponent.getRealPosition());
PositionVector targetPosition = route.getFirst();
Double distanceToTargetPosition = targetPosition.distanceTo(currentPosition);
// If target point is reached within a 1 meter margin, we remove that point from the list
if(distanceToTargetPosition < 0.1 || distanceToTargetPosition < currentSpeed)
{
route.removeFirst();
topologyComponent.getActuatorEnergyComponent().useActuator(0.5);
topologyComponent.updateCurrentLocation(targetPosition); // triggers energy consumption for last distance
currentSpeed = 0;
topologyComponent.getActuatorEnergyComponent().useActuator(0); // now hover
locationReached(targetPosition);
return;
double thrust = 0;
direction = new PositionVector(0,0,1);
double distz = 100 - position.getZ();
if(distz < 100) {
double time = ((double) timeBetweenMovementOperations) / ((double) Time.SECOND);
// ASCENSION TO SAFETY HEIGHT
thrust = motor.requestThrust(motor.getMaxThrust());
double acc = ((thrust - hoverThrustRequired()) / mass ) - currentDrag();
double speed = 0;
if(acc < 0.1) {
// normal flight
speed = verticalAscentMaxVelocity();
}
else {
// acceleration
speed = currentSpeed + acc * time;
}
System.out.println("ACCELERATION : " + acc);
System.out.println("SPEED : " + speed);
//double dist = 0.5 * acc * (timeBetweenMovementOperations / Time.SECOND) * (timeBetweenMovementOperations / Time.SECOND);
double dist = currentSpeed * time;
//double safetydistance = speed
//System.out.println();
position.add(new PositionVector(0,0,dist));
System.out.println("NEW POSITION : " + position);
topologyComponent.updateCurrentLocation(position);
}
else {
thrust = motor.requestThrust(hoverThrustRequired());
topologyComponent.updateCurrentLocation(position);
}
double timefactor = timeBetweenMovementOperations / Time.SECOND;
currentSpeed = Math.min(distanceToTargetPosition, preferredCruiseSpeed);
PositionVector direction = new PositionVector(targetPosition);
direction.subtract(currentPosition);
direction.normalize();
direction.multiplyScalar(currentSpeed * timefactor);
PositionVector newPosition = new PositionVector(currentPosition);
newPosition.add(direction);
topologyComponent.getActuatorEnergyComponent().useActuator(1);
topologyComponent.updateCurrentLocation(newPosition);
// PositionVector directionToTarget = new PositionVector(route.getFirst());
// directionToTarget.subtract(position);
//
// double distanceToTargetPosition = directionToTarget.getLength();
// // If target point is reached within a 1 meter margin, we remove that point from the list
// if(distanceToTargetPosition < 0.1 || distanceToTargetPosition < currentSpeed)
// {
// route.removeFirst();
//
// topologyComponent.updateCurrentLocation(position);
// currentSpeed = 0;
//
// locationReached(position);
// return;
// }
//
// double timefactor = timeBetweenMovementOperations / Time.SECOND;
//
// currentSpeed = Math.min(distanceToTargetPosition, preferredSpeed);
//
// direction.normalize();
// direction.multiplyScalar(currentSpeed * timefactor);
//
// PositionVector newPosition = new PositionVector(position);
// newPosition.add(direction);
//
// topologyComponent.updateCurrentLocation(newPosition);
}
//System.out.println(Simulator.getFormattedTime(Simulator.getCurrentTime()) + " | " + topologyComponent);
}
@Override
public void setPreferredSpeed(double v_pref) {
this.preferredSpeed = v_pref;
}
@Override
public double getCurrentSpeed() {
return currentSpeed;
}
/**
* Trigger the callback function, if there is a valid callback
*
......@@ -179,7 +304,19 @@ public class SimpleMutlicopterMovement implements UAVMovementModel {
locationCallbacks.clear();
}
@Override
public double minimumVelocity() {
return 0;
}
@Override
public double estimatePowerConsumption(double velocity) {
// TODO Auto-generated method stub
return 0;
}
}
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* PeerfactSim.KOM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.topology.movement.aerial;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
import org.apache.commons.math3.geometry.euclidean.twod.Vector2D;
import de.tud.kom.p2psim.api.energy.Battery;
import de.tud.kom.p2psim.api.topology.movement.UAVMovementModel;
import de.tud.kom.p2psim.impl.energy.components.StatelessMotorComponent;
import de.tud.kom.p2psim.impl.topology.component.UAVTopologyComponent;
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
import de.tudarmstadt.maki.simonstrator.api.Time;
import de.tudarmstadt.maki.simonstrator.api.uavsupport.callbacks.ReachedLocationCallback;
/**
* Local movement logic specifically designs the movement for multicopter UAVs.
* This simple movement logic uses straight forward movement with the maximum speed available.
*
* @author Julian Zobel
* @version 1.0, 11.09.2018
*/
public class SimpleMulticopterMovement implements UAVMovementModel {
private UAVTopologyComponent topologyComponent;
private double currentAngleOfAttack;
private double currentSpeed;
private double targetSpeed;
private LinkedList<PositionVector> route = new LinkedList<>();
private Map<PositionVector, ReachedLocationCallback> locationCallbacks = new LinkedHashMap<>(); // TODO callback interface
private StatelessMotorComponent motor;
private double mass = 1.465; // kg
private final double airdensity = 1.2045; // kg/m^3
private final double gravity = 9.807; // m/s^2
private double A_top = 0.245; // m^2
private double A_front = 0.1; // m^2
private double dragCoefficient = 0.7;
private double maxPitchAngle = Math.toRadians(60); // 45° max angle
private double descentVelocityMax = 5; // m/s
private double maxTurnAngle = Math.toRadians(90); // 90° per second turn angle
public SimpleMulticopterMovement(UAVTopologyComponent topologyComponent) {
this.topologyComponent = topologyComponent;
}
boolean first = true;
@Override
public void move(long timeBetweenMovementOperations) {
if(motor.isOn() && !route.isEmpty()) {
PositionVector position = new PositionVector(topologyComponent.getRealPosition());
PositionVector target = route.getFirst();
double distanceToTargetPosition = position.distanceTo(target);
// If target point is reached within a 1 meter margin, we remove that point from the list
if(distanceToTargetPosition < 0.1 || distanceToTargetPosition < currentSpeed)
{
target = route.removeFirst();
if(route.isEmpty()) {
// go to hover mode
topologyComponent.updateCurrentLocation(target.clone());
currentSpeed = 0;
motor.requestThrust(hoverThrustRequired());
PositionVector direction = topologyComponent.getCurrentDirection().clone();
direction.setEntry(2, 0);
topologyComponent.updateCurrentDirection(direction);
locationReached(topologyComponent.getCurrentLocation());
return;
}
else {
// get to speed
if(targetSpeed > 0 && targetSpeed < horizontalMaxVelocity()) {
motor.requestThrust(estimateRequiredThrust(targetSpeed));
currentSpeed = targetSpeed;
}
else {
motor.requestThrust(horizontalMaxVelocityRequiredTotalThrust());
currentSpeed = horizontalMaxVelocity();
}
long timeUntilReachedLocation = (long) (distanceToTargetPosition / currentSpeed) * Time.SECOND;
target = route.getFirst();
PositionVector directionToTarget = new PositionVector(target);
directionToTarget.subtract(position);
double timefactor = timeUntilReachedLocation / Time.SECOND;
directionToTarget.normalize();
topologyComponent.updateCurrentDirection(directionToTarget.clone());
directionToTarget.multiplyScalar(currentSpeed * timefactor);
PositionVector newPosition = new PositionVector(position);
newPosition.add(directionToTarget);
topologyComponent.updateCurrentLocation(newPosition);
if(timeUntilReachedLocation < timeBetweenMovementOperations) {
this.move(timeBetweenMovementOperations - timeUntilReachedLocation);
}
}
}
else {
double timefactor = timeBetweenMovementOperations / Time.SECOND;
// get to speed
if(targetSpeed > 0 && targetSpeed < horizontalMaxVelocity()) {
motor.requestThrust(estimateRequiredThrust(targetSpeed));
currentSpeed = targetSpeed;
}
else {
motor.requestThrust(horizontalMaxVelocityRequiredTotalThrust());
currentSpeed = horizontalMaxVelocity();
}
PositionVector directionToTarget = new PositionVector(target);
directionToTarget.subtract(position);
directionToTarget.normalize();
if(directionToTarget.getX() != 0 || directionToTarget.getY() != 0) {
topologyComponent.updateCurrentDirection(directionToTarget.clone());
}
directionToTarget.multiplyScalar(currentSpeed * timefactor);
PositionVector newPosition = new PositionVector(position);
newPosition.add(directionToTarget);
topologyComponent.updateCurrentLocation(newPosition);
}
}
else if(motor.isOn()) {
if(currentSpeed != 0) {
throw new UnsupportedOperationException("no route but speed not 0?");
}
PositionVector position = new PositionVector(topologyComponent.getRealPosition());
if(position.getAltitude() == 0) {
motor.requestThrust(0);
}
else {
motor.requestThrust(hoverThrustRequired());
}
}
}
/*
*
*/
public double verticalDescentMaxThrust() {
// m * g - 0.5 * p * C * A * v^2
return hoverThrustRequired() - 0.5 * bodyDrag(0, new PositionVector(0,0,1)) * descentVelocityMax * descentVelocityMax;
}
public double verticalAscentMaxAcceleration() {
return (motor.getMaxThrust() - hoverThrustRequired()) / mass;
}
public double verticalAscentMaxVelocity() {
double maxThrust = motor.getMaxThrust();
return Math.sqrt(2.0 * (maxThrust - hoverThrustRequired()) / bodyDrag(0, new PositionVector(0,0,1)));
}
public double hoverThrustRequired() {
return mass * gravity;
}
public double horizontalMaxVelocity() {
double horizontalThrust = horizontalComponentMaxThrust();
double maxVelocity = Math.sqrt( (2.0 * horizontalThrust) / bodyDrag(maxPitchAngle, new PositionVector(1,0,0)));
return maxVelocity;
}
public double horizontalComponentMaxThrust() {
// hoverthrust / cos => amount of thrust in horizonal direction with °angle
double stableAltitudeMaximumTotalThrust = horizontalMaxVelocityRequiredTotalThrust();
// fraction of total thrust in horizonal (forward) direction with °angle
double maximumHorizontalThrustStableAltitude = stableAltitudeMaximumTotalThrust * Math.sin(maxPitchAngle);
return maximumHorizontalThrustStableAltitude;
}
public double horizontalMaxVelocityRequiredTotalThrust() {
return hoverThrustRequired() / Math.cos(maxPitchAngle);
}
public double bodyDrag(double angleRadians, PositionVector direction) {
return airdensity * dragCoefficient * areaExposedToDrag(angleRadians, direction);
}
public double areaExposedToDrag(double angleRadians, PositionVector direction) {
Vector2D v = new Vector2D(Math.abs(direction.getX()) + Math.abs(direction.getY()), Math.abs(direction.getZ()));
v = v.normalize();
double areaExposedFront = v.getX() * (Math.sin(angleRadians) * A_top + Math.cos(angleRadians) * A_front );
double areaExposedTop = v.getY() * (Math.cos(angleRadians) * A_top + Math.sin(angleRadians) * A_front);
return areaExposedFront + areaExposedTop;
}
/*
* F_drag [N] = 0.5 * p * C_drag * A * v^2
*/
public double currentDrag() {
return 0.5 * bodyDrag(currentAngleOfAttack, topologyComponent.getCurrentDirection()) * currentSpeed * currentSpeed;
}
/**
* Calculate the drag induced on the UAV with a given velocity and an angle of attack (in radians) moving forward horizontally.
*
* @param velocity
* @param angleInRadians
* @return
*/
private double forwardDrag(double velocity, double angleInRadians) {
return 0.5 * bodyDrag(angleInRadians, new PositionVector(1,0,0)) * velocity * velocity;
}
/*
*
*/
@Override
public void setMotorControl(StatelessMotorComponent motor) {
this.motor = motor;
}
@Override
public void setPreferredSpeed(double v_pref) {
this.targetSpeed = v_pref;
}
@Override
public double getCurrentSpeed() {
return currentSpeed;
}
/**
* Trigger the callback function, if there is a valid callback
*
* @param position
*/
private void locationReached(PositionVector position) {
if(locationCallbacks.containsKey(position)) {
locationCallbacks.get(position).reachedLocation();
}
}
@Override
public void setTargetLocation(PositionVector target,
ReachedLocationCallback reachedLocationCallback) {
route.clear();
route.add(target);
if(reachedLocationCallback != null)
locationCallbacks.put(target, reachedLocationCallback);
}
@Override
public void setTargetLocationRoute(LinkedList<PositionVector> route,
ReachedLocationCallback reachedLocationCallback) {
this.route.clear();
this.route.addAll(route);
if(reachedLocationCallback != null)
locationCallbacks.put(route.getLast(), reachedLocationCallback);
}
@Override
public void addTargetLocation(PositionVector target,
ReachedLocationCallback reachedLocationCallback) {
route.add(target);
if(reachedLocationCallback != null)
locationCallbacks.put(target, reachedLocationCallback);
}
@Override
public LinkedList<PositionVector> getTargetLocations() {
LinkedList<PositionVector> copy = new LinkedList<>();
for (PositionVector pv : route) {
copy.add(pv.clone());
}
return copy;
}
@Override
public void removeTargetLocations() {
route.clear();
locationCallbacks.clear();
}
@Override
public double minimumVelocity() {
return minimumHorizontalVelocity();
}
public double minimumHorizontalVelocity() {
return Math.sqrt(2 * hoverThrustRequired() * Math.tan(Math.toRadians(0.25)) / bodyDrag(Math.toRadians(0.25), new PositionVector(1,0,0)));
}
@Override
public double estimatePowerConsumption(double velocity) {
if(velocity == 0) {
return motor.estimatePowerConsumptionWatt(hoverThrustRequired());
}
else if(velocity > horizontalMaxVelocity()) {
return -1;
}
else if(velocity < minimumHorizontalVelocity()) {
return -1;
}
else {
double estimateAngle = estimatePitchAngleForVelocity(velocity);
double estimatedDrag = forwardDrag(velocity, estimateAngle);
double requiredThrust = Math.sqrt(hoverThrustRequired() * hoverThrustRequired() + estimatedDrag * estimatedDrag);
double wattage = motor.estimatePowerConsumptionWatt(requiredThrust);
return wattage;
}
}
public double estimateRequiredThrust(double velocity) {
if(velocity == 0) {
return motor.estimatePowerConsumptionWatt(hoverThrustRequired());
}
else if(velocity > horizontalMaxVelocity()) {
return -1;
}
else if(velocity < minimumHorizontalVelocity()) {
return -1;
}
else {
double estimateAngle = estimatePitchAngleForVelocity(velocity);
double estimatedDrag = forwardDrag(velocity, estimateAngle);
double requiredThrust = Math.sqrt(hoverThrustRequired() * hoverThrustRequired() + estimatedDrag * estimatedDrag);
return requiredThrust;
}
}
/**
* Estimate the pitch angle (angle of attack) required to get the target velocity.
* Angle precision is 1/4 degree.
*
* @param velocity
* @return
*/
private double estimatePitchAngleForVelocity(double velocity) {
int low = 0;
int high = Integer.MAX_VALUE;
double vsquared = (velocity * velocity);
for(int i = 0; i <= ((int) Math.toDegrees(maxPitchAngle)); i++) {
double v2 = 2 * hoverThrustRequired() * Math.tan(Math.toRadians(i)) / bodyDrag(Math.toRadians(i), new PositionVector(1,0,0));
if(v2 > vsquared && i < high) {
high = i;
}
else if(v2 < vsquared && i >= low) {
low = i;
}
else if(v2 == vsquared ) {
return Math.toRadians(i);
}
}
if(high < Integer.MAX_VALUE) {
double lo = low;
double hi = high;
double nearest = -1;
double nearestDiff = Double.MAX_VALUE;
double step = (hi - lo) / 4;
for(int i = 0; i < 4; i++) {
double d = lo + i * step;
double v2 = 2 * hoverThrustRequired() * Math.tan(Math.toRadians(d)) / bodyDrag(Math.toRadians(d), new PositionVector(1,0,0));
double diff = Math.abs(((velocity * velocity) - v2));
if(diff < nearestDiff || (lo == 0 && i == 1)) {
nearestDiff = diff;
nearest = d;
}
}
return Math.toRadians(nearest);
}
return maxPitchAngle;
}
}
......@@ -158,10 +158,7 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
*/
localMovementStrategy
.setScaleFactor(timeBetweenMoveOperation / (double) Time.SECOND);
List<AttractionPoint> attractionPoints = attractionGenerator
.getAttractionPoints();
transition.setAttractionPoints(attractionPoints);
transition.addAttractionAssignmentListener(this);
// This adds the mobile hosts (smartphones/users) to the transition
......@@ -197,13 +194,7 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
public AttractionPoint getTargetLocation(SimLocationActuator actuator) {
return transition.getAssignment(actuator);
}
@Override
public Set<AttractionPoint> getAllAttractionPoints()
throws UnsupportedOperationException {
return transition.getAllAttractionPoints();
}
private void checkConfiguration() {
if (localMovementStrategy == null) {
throw new ConfigurationException(
......@@ -362,6 +353,6 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
* @return
*/
public List<AttractionPoint> getAttractionPoints() {
return new Vector<AttractionPoint>(transition.getAllAttractionPoints());
return new Vector<AttractionPoint>(IAttractionGenerator.attractionPoints);
}
}
......@@ -78,8 +78,7 @@ public class ModularMultiTypeMovementModel extends ModularMovementModel
suppressListenerNotify = true;
for(ITransitionStrategy strategy : supportedTransitions.values())
{
strategy.setAttractionPoints(transition.getAllAttractionPoints());
{
strategy.addAttractionAssignmentListener(this);
for (SimLocationActuator ms : moveableHosts) {
strategy.addComponent(ms);
......
......@@ -71,6 +71,8 @@ public class AttractionPointImpl extends BasicAttractionPoint {
@Override
public boolean equals(Object obj) {
if(obj == null)
return false;
if (this == obj)
return true;
if (getClass() != obj.getClass())
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment