simulation listener enhancements
This commit is contained in:
parent
159dc25c02
commit
53d5f2163d
@ -1,3 +1,11 @@
|
||||
2011-06-26 Sampo Niskanen
|
||||
|
||||
* [BUG] Original rocket was modified when sim.listener modified rocket
|
||||
|
||||
2011-06-18 Sampo Niskanen
|
||||
|
||||
* Merged l10n branch into trunk, initial l10n support
|
||||
|
||||
2011-06-10 Sampo Niskanen
|
||||
|
||||
* Released version 1.1.5
|
||||
|
21
src-extra/AirStart.java
Normal file
21
src-extra/AirStart.java
Normal file
@ -0,0 +1,21 @@
|
||||
import net.sf.openrocket.simulation.SimulationStatus;
|
||||
import net.sf.openrocket.simulation.exception.SimulationException;
|
||||
import net.sf.openrocket.simulation.listeners.AbstractSimulationListener;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
|
||||
/**
|
||||
* Simulation listener that launches a rocket from a specific altitude.
|
||||
*/
|
||||
public class AirStart extends AbstractSimulationListener {
|
||||
|
||||
/** Launch altitude */
|
||||
private static final double ALTITUDE = 1000.0;
|
||||
|
||||
@Override
|
||||
public void startSimulation(SimulationStatus status) throws SimulationException {
|
||||
Coordinate position = status.getRocketPosition();
|
||||
position = position.add(0, 0, ALTITUDE);
|
||||
status.setRocketPosition(position);
|
||||
}
|
||||
|
||||
}
|
@ -61,8 +61,12 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
|
||||
|
||||
SimulationListenerHelper.fireStartSimulation(status);
|
||||
// Get originating position (in case listener has modified launch position)
|
||||
Coordinate origin = status.getRocketPosition();
|
||||
Coordinate originVelocity = status.getRocketVelocity();
|
||||
|
||||
try {
|
||||
double maxAlt = Double.NEGATIVE_INFINITY;
|
||||
|
||||
// Start the simulation
|
||||
while (handleEvents()) {
|
||||
@ -91,17 +95,24 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
status.getConfiguration().getRocket(),
|
||||
new Pair<Double, Double>(oldAlt, status.getRocketPosition().z)));
|
||||
|
||||
if (status.getRocketPosition().z > maxAlt) {
|
||||
maxAlt = status.getRocketPosition().z;
|
||||
}
|
||||
|
||||
|
||||
// Position relative to start location
|
||||
Coordinate relativePosition = status.getRocketPosition().sub(origin);
|
||||
|
||||
// Add appropriate events
|
||||
if (!status.isLiftoff()) {
|
||||
|
||||
// Avoid sinking into ground before liftoff
|
||||
if (status.getRocketPosition().z < 0) {
|
||||
status.setRocketPosition(Coordinate.NUL);
|
||||
status.setRocketVelocity(Coordinate.NUL);
|
||||
if (relativePosition.z < 0) {
|
||||
status.setRocketPosition(origin);
|
||||
status.setRocketVelocity(originVelocity);
|
||||
}
|
||||
// Detect lift-off
|
||||
if (status.getRocketPosition().z > 0.01) {
|
||||
if (relativePosition.z > 0.02) {
|
||||
addEvent(new FlightEvent(FlightEvent.Type.LIFTOFF, status.getSimulationTime()));
|
||||
}
|
||||
|
||||
@ -118,13 +129,13 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
|
||||
// Check for launch guide clearance
|
||||
if (!status.isLaunchRodCleared() &&
|
||||
status.getRocketPosition().length() > status.getSimulationConditions().getLaunchRodLength()) {
|
||||
relativePosition.length() > status.getSimulationConditions().getLaunchRodLength()) {
|
||||
addEvent(new FlightEvent(FlightEvent.Type.LAUNCHROD, status.getSimulationTime(), null));
|
||||
}
|
||||
|
||||
|
||||
// Check for apogee
|
||||
if (!status.isApogeeReached() && status.getRocketPosition().z < oldAlt - 0.001) {
|
||||
if (!status.isApogeeReached() && status.getRocketPosition().z < maxAlt - 0.01) {
|
||||
addEvent(new FlightEvent(FlightEvent.Type.APOGEE, status.getSimulationTime(),
|
||||
status.getConfiguration().getRocket()));
|
||||
}
|
||||
|
@ -436,7 +436,7 @@ public class GUISimulationConditions implements ChangeSource, Cloneable {
|
||||
public SimulationConditions toSimulationConditions() {
|
||||
SimulationConditions conditions = new SimulationConditions();
|
||||
|
||||
conditions.setRocket(getRocket());
|
||||
conditions.setRocket((Rocket) getRocket().copy());
|
||||
conditions.setMotorConfigurationID(getMotorConfigurationID());
|
||||
conditions.setLaunchRodLength(getLaunchRodLength());
|
||||
conditions.setLaunchRodAngle(getLaunchRodAngle());
|
||||
|
@ -0,0 +1,38 @@
|
||||
package net.sf.openrocket.simulation.listeners.example;
|
||||
|
||||
import net.sf.openrocket.simulation.SimulationStatus;
|
||||
import net.sf.openrocket.simulation.exception.SimulationException;
|
||||
import net.sf.openrocket.simulation.listeners.AbstractSimulationListener;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
|
||||
/**
|
||||
* Simulation listener that launches a rocket from a specific altitude.
|
||||
* <p>
|
||||
* The altitude is read from the system property "openrocket.airstart.altitude"
|
||||
* if defined, otherwise a default altitude of 1000 meters is used.
|
||||
*/
|
||||
public class AirStart extends AbstractSimulationListener {
|
||||
|
||||
/** Default launch altitude */
|
||||
private static final double DEFAULT_ALTITUDE = 1000.0;
|
||||
|
||||
@Override
|
||||
public void startSimulation(SimulationStatus status) throws SimulationException {
|
||||
|
||||
// Get the launch altitude
|
||||
double altitude;
|
||||
String arg = System.getProperty("openrocket.airstart.altitude");
|
||||
try {
|
||||
altitude = Double.parseDouble(arg);
|
||||
} catch (RuntimeException e) {
|
||||
altitude = DEFAULT_ALTITUDE;
|
||||
}
|
||||
|
||||
// Modify launch position
|
||||
Coordinate position = status.getRocketPosition();
|
||||
position = position.add(0, 0, altitude);
|
||||
status.setRocketPosition(position);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,10 +1,13 @@
|
||||
package net.sf.openrocket.simulation.listeners.haisu;
|
||||
package net.sf.openrocket.simulation.listeners.example;
|
||||
|
||||
import net.sf.openrocket.aerodynamics.FlightConditions;
|
||||
import net.sf.openrocket.rocketcomponent.FinSet;
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||
import net.sf.openrocket.simulation.FlightDataType;
|
||||
import net.sf.openrocket.simulation.SimulationStatus;
|
||||
import net.sf.openrocket.simulation.exception.SimulationException;
|
||||
import net.sf.openrocket.simulation.listeners.AbstractSimulationListener;
|
||||
import net.sf.openrocket.unit.UnitGroup;
|
||||
import net.sf.openrocket.util.MathUtil;
|
||||
|
||||
/**
|
||||
@ -15,15 +18,29 @@ import net.sf.openrocket.util.MathUtil;
|
||||
*/
|
||||
public class RollControlListener extends AbstractSimulationListener {
|
||||
|
||||
private static final double DELTA_T = 0.01;
|
||||
// Name of control fin set
|
||||
private static final String CONTROL_FIN_NAME = "CONTROL";
|
||||
|
||||
// Define custom flight data type
|
||||
private static final FlightDataType FIN_CANT_TYPE = FlightDataType.getType("Control fin cant",
|
||||
UnitGroup.UNITS_ANGLE);
|
||||
|
||||
// Simulation time at which PID controller is activated
|
||||
private static final double START_TIME = 0.5;
|
||||
|
||||
// Desired roll rate (rad/sec)
|
||||
private static final double SETPOINT = 0.0;
|
||||
|
||||
private static final double TURNRATE = 10 * Math.PI / 180; // per second
|
||||
// Maximum control fin turn rate (rad/sec)
|
||||
private static final double TURNRATE = 10 * Math.PI / 180;
|
||||
|
||||
// Maximum control fin angle (rad)
|
||||
private static final double MAX_ANGLE = 15 * Math.PI / 180;
|
||||
|
||||
|
||||
/*
|
||||
* PID parameters
|
||||
*
|
||||
* At M=0.3 KP oscillation threshold between 0.35 and 0.4. Good KI=3
|
||||
* At M=0.6 KP oscillation threshold between 0.07 and 0.08 Good KI=2
|
||||
* At M=0.9 KP oscillation threshold between 0.013 and 0.014 Good KI=0.5
|
||||
@ -32,58 +49,63 @@ public class RollControlListener extends AbstractSimulationListener {
|
||||
private static final double KI = 0.2;
|
||||
|
||||
|
||||
private static final double MAX_ANGLE = 15 * Math.PI / 180;
|
||||
|
||||
|
||||
|
||||
|
||||
private double rollrate;
|
||||
|
||||
private double prevTime = 0;
|
||||
private double intState = 0;
|
||||
|
||||
private double finPosition = 0;
|
||||
|
||||
|
||||
public RollControlListener() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlightConditions postFlightConditions(SimulationStatus status, FlightConditions flightConditions) {
|
||||
// Store the current roll rate for later use
|
||||
rollrate = flightConditions.getRollRate();
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void postStep(SimulationStatus status) {
|
||||
public void postStep(SimulationStatus status) throws SimulationException {
|
||||
|
||||
if (status.getSimulationTime() < START_TIME)
|
||||
// Activate PID controller only after a specific time
|
||||
if (status.getSimulationTime() < START_TIME) {
|
||||
prevTime = status.getSimulationTime();
|
||||
return;
|
||||
}
|
||||
|
||||
// PID controller
|
||||
// Find the fin set named CONTROL
|
||||
FinSet finset = null;
|
||||
for (RocketComponent c : status.getConfiguration()) {
|
||||
if ((c instanceof FinSet) && (c.getName().equals("CONTROL"))) {
|
||||
if ((c instanceof FinSet) && (c.getName().equals(CONTROL_FIN_NAME))) {
|
||||
finset = (FinSet) c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (finset == null) {
|
||||
throw new RuntimeException("CONTROL fin not found");
|
||||
throw new SimulationException("A fin set with name '" + CONTROL_FIN_NAME + "' was not found");
|
||||
}
|
||||
|
||||
|
||||
// Determine time step
|
||||
double deltaT = status.getSimulationTime() - prevTime;
|
||||
prevTime = status.getSimulationTime();
|
||||
|
||||
|
||||
// PID controller
|
||||
double error = SETPOINT - rollrate;
|
||||
|
||||
|
||||
error = Math.signum(error) * error * error; //// pow2(error)
|
||||
|
||||
double p = KP * error;
|
||||
intState += error * DELTA_T;
|
||||
intState += error * deltaT;
|
||||
double i = KI * intState;
|
||||
|
||||
double value = p + i;
|
||||
|
||||
|
||||
// Clamp the fin angle between -MAX_ANGLE and MAX_ANGLE
|
||||
if (Math.abs(value) > MAX_ANGLE) {
|
||||
System.err.printf("Attempting to set angle %.1f at t=%.3f, clamping.\n",
|
||||
value * 180 / Math.PI, status.getSimulationTime());
|
||||
@ -91,19 +113,16 @@ public class RollControlListener extends AbstractSimulationListener {
|
||||
}
|
||||
|
||||
|
||||
// Limit the fin turn rate
|
||||
if (finPosition < value) {
|
||||
finPosition = Math.min(finPosition + TURNRATE * DELTA_T, value);
|
||||
finPosition = Math.min(finPosition + TURNRATE * deltaT, value);
|
||||
} else {
|
||||
finPosition = Math.max(finPosition - TURNRATE * DELTA_T, value);
|
||||
}
|
||||
|
||||
if (MathUtil.equals(status.getSimulationTime() * 10, Math.rint(status.getSimulationTime() * 10))) {
|
||||
System.err.printf("t=%.3f angle=%.1f current=%.1f\n", status.getSimulationTime(),
|
||||
value * 180 / Math.PI, finPosition * 180 / Math.PI);
|
||||
finPosition = Math.max(finPosition - TURNRATE * deltaT, value);
|
||||
}
|
||||
|
||||
// Set the control fin cant and store the data
|
||||
finset.setCantAngle(finPosition);
|
||||
status.getFlightData().setValue(FIN_CANT_TYPE, finPosition);
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user