/*
* 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 .
*
*/
package de.tud.kom.p2psim.impl.topology.movement.aerial;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
import de.tud.kom.p2psim.api.topology.movement.UAVMovementModel;
import de.tud.kom.p2psim.impl.energy.components.ActuatorComponent;
import de.tud.kom.p2psim.impl.energy.components.StatefulActuatorComponent;
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 for UAVs.
* This simple movement logic uses straight forward movement with the set speed (up to a max).
* Energy consumption is based on state actuators.
*
* @author Julian Zobel
* @version 1.1, 14.01.2020
*/
public class SimpleMulticopterMovement implements UAVMovementModel {
private UAVTopologyComponent topologyComponent;
private double velocity;
private double targetVelocity;
private double maximumHorizontalVelocity;
private double maximumVerticalVelocity;
// TODO currently not used
private double minimumHorizontalVelocity;
private double minimumVerticalVelocity;
private double optimalHorizontalVelocity;
private LinkedList route = new LinkedList<>();
private Map locationCallbacks = new LinkedHashMap<>();
private StatefulActuatorComponent motor;
public SimpleMulticopterMovement(UAVTopologyComponent topologyComponent, double maximumHorizontalVelocity, double optimalHorizontalVelocity,
double maximumVerticalVelocity, double minimumHorizontalVelocity, double minimumVerticalVelocity) {
this.topologyComponent = topologyComponent;
this.maximumHorizontalVelocity = maximumHorizontalVelocity;
this.optimalHorizontalVelocity = optimalHorizontalVelocity;
this.maximumVerticalVelocity = maximumVerticalVelocity;
this.minimumHorizontalVelocity = minimumHorizontalVelocity;
this.minimumVerticalVelocity = minimumVerticalVelocity;
}
@Override
public void move(long timeBetweenMovementOperations) {
if(motor.isOn() && !route.isEmpty()) {
PositionVector currentPosition = 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 < velocity)
{
route.removeFirst();
topologyComponent.updateCurrentLocation(targetPosition); // triggers energy consumption for last distance
velocity = 0;
motor.useActuator(0);
locationReached(targetPosition);
return;
}
double timefactor = timeBetweenMovementOperations / Time.SECOND;
velocity = Math.min(distanceToTargetPosition, targetVelocity);
PositionVector direction = new PositionVector(targetPosition);
direction.subtract(currentPosition);
direction.normalize();
direction.multiplyScalar(velocity * timefactor);
PositionVector newPosition = new PositionVector(currentPosition);
newPosition.add(direction);
if(velocity <= optimalHorizontalVelocity) {
motor.useActuator(1.0);
}
else {
motor.useActuator(2.0);
}
topologyComponent.updateCurrentLocation(newPosition);
}
else if(motor.isOn()) {
if(velocity != 0) {
throw new UnsupportedOperationException("no route but speed not 0?");
}
PositionVector position = new PositionVector(topologyComponent.getRealPosition());
if(position.getAltitude() == 0) {
motor.turnOff();
}
else {
motor.useActuator(0);
}
}
}
@Override
public void setTargetVelocity(double v_pref) {
this.targetVelocity = v_pref;
}
@Override
public double getCurrentVelocity() {
return velocity;
}
/**
* 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 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 getTargetLocations() {
LinkedList copy = new LinkedList<>();
for (PositionVector pv : route) {
copy.add(pv.clone());
}
return copy;
}
@Override
public void removeTargetLocations() {
route.clear();
locationCallbacks.clear();
}
@Override
public double estimatePowerConsumptionWatt(double velocity) {
double wattage = 0;
if(velocity == 0) {
wattage = motor.estimateEnergyConsumptionWatt(0);
}
else if( velocity <= optimalHorizontalVelocity){
wattage = motor.estimateEnergyConsumptionWatt(1);
}
else {
wattage = motor.estimateEnergyConsumptionWatt(2);
}
return wattage;
}
@Override
public void setMotorControl(ActuatorComponent motor) {
this.motor = (StatefulActuatorComponent) motor;
}
@Override
public double getVerticalAscentMaxVelocity() {
return maximumVerticalVelocity;
}
@Override
public double getHorizontalMaxVelocity() {
return maximumHorizontalVelocity;
}
@Override
public double getHorizontalMinVelocity() {
return 0;
}
/**
* Factory for this movement model
*
* @author Julian Zobel
* @version 1.0, 14.01.2020
*/
public static class Factory implements AerialMovementModelFactory {
private double maximumHorizontalVelocity = 15;
public void setMaximumHorizontalVelocity(double maximumHorizontalVelocity) {
this.maximumHorizontalVelocity = maximumHorizontalVelocity;
}
private double optimalHorizontalVelocity = 10;
public void setOptimalHorizontalVelocity(double optimalHorizontalVelocity) {
this.optimalHorizontalVelocity = optimalHorizontalVelocity;
}
private double maximumVerticalVelocity = 5;
public void setMaximumVerticalVelocity(double maximumVerticalVelocity) {
this.maximumVerticalVelocity = maximumVerticalVelocity;
}
private double minimumHorizontalVelocity = 15;
public void setMinimumHorizontalVelocity(double minimumHorizontalVelocity) {
this.minimumHorizontalVelocity = minimumHorizontalVelocity;
}
private double minimumVerticalVelocity = 5;
public void setMinimumVerticalVelocity(double minimumVerticalVelocity) {
this.minimumVerticalVelocity = minimumVerticalVelocity;
}
public UAVMovementModel createComponent(UAVTopologyComponent topologyComponent) {
return new SimpleMulticopterMovement(topologyComponent, maximumHorizontalVelocity, optimalHorizontalVelocity,
maximumVerticalVelocity, minimumHorizontalVelocity, minimumVerticalVelocity);
}
}
@Override
public double estimateOptimalSpeed() {
return optimalHorizontalVelocity;
}
}