1 package net.sf.openrocket.simulation.listeners.haisu;
3 import net.sf.openrocket.aerodynamics.FlightConditions;
4 import net.sf.openrocket.rocketcomponent.FinSet;
5 import net.sf.openrocket.rocketcomponent.RocketComponent;
6 import net.sf.openrocket.simulation.SimulationStatus;
7 import net.sf.openrocket.simulation.listeners.AbstractSimulationListener;
8 import net.sf.openrocket.util.MathUtil;
11 * An example listener that applies a PI-controller to adjust the cant of fins
12 * named "CONTROL" to stop the rocket from rolling.
14 * @author Sampo Niskanen <sampo.niskanen@iki.fi>
16 public class RollControlListener extends AbstractSimulationListener {
18 private static final double DELTA_T = 0.01;
19 private static final double START_TIME = 0.5;
21 private static final double SETPOINT = 0.0;
23 private static final double TURNRATE = 10 * Math.PI / 180; // per second
27 * At M=0.3 KP oscillation threshold between 0.35 and 0.4. Good KI=3
28 * At M=0.6 KP oscillation threshold between 0.07 and 0.08 Good KI=2
29 * At M=0.9 KP oscillation threshold between 0.013 and 0.014 Good KI=0.5
31 private static final double KP = 0.007;
32 private static final double KI = 0.2;
35 private static final double MAX_ANGLE = 15 * Math.PI / 180;
40 private double rollrate;
42 private double intState = 0;
44 private double finPosition = 0;
47 public RollControlListener() {
51 public FlightConditions postFlightConditions(SimulationStatus status, FlightConditions flightConditions) {
52 rollrate = flightConditions.getRollRate();
57 public void postStep(SimulationStatus status) {
59 if (status.getSimulationTime() < START_TIME)
64 for (RocketComponent c : status.getConfiguration()) {
65 if ((c instanceof FinSet) && (c.getName().equals("CONTROL"))) {
71 throw new RuntimeException("CONTROL fin not found");
75 double error = SETPOINT - rollrate;
78 error = Math.signum(error) * error * error; //// pow2(error)
80 double p = KP * error;
81 intState += error * DELTA_T;
82 double i = KI * intState;
87 if (Math.abs(value) > MAX_ANGLE) {
88 System.err.printf("Attempting to set angle %.1f at t=%.3f, clamping.\n",
89 value * 180 / Math.PI, status.getSimulationTime());
90 value = MathUtil.clamp(value, -MAX_ANGLE, MAX_ANGLE);
94 if (finPosition < value) {
95 finPosition = Math.min(finPosition + TURNRATE * DELTA_T, value);
97 finPosition = Math.max(finPosition - TURNRATE * DELTA_T, value);
100 if (MathUtil.equals(status.getSimulationTime() * 10, Math.rint(status.getSimulationTime() * 10))) {
101 System.err.printf("t=%.3f angle=%.1f current=%.1f\n", status.getSimulationTime(),
102 value * 180 / Math.PI, finPosition * 180 / Math.PI);
105 finset.setCantAngle(finPosition);