#include "Vehicle.h" #include "outVector.h" #include void burnStartTimeCalc(struct Vehicle &); void pidController(struct Vehicle &, struct Vehicle &); void TVC(struct Vehicle &, struct Vehicle &); void vehicleDynamics(struct Vehicle &, struct Vehicle &); void state2vec(struct Vehicle &, struct Vehicle &, struct outVector &); double derivative(double current, double previous, double step); double integral(double currentChange, double prevValue, double dt); double limit(double value, double upr, double lwr); void getThrust(struct Vehicle &); // Any parameters that are constants should be declared here instead of // buried in code double const dt = 0.01; double const g = -9.81; void burnStartTimeCalc(Vehicle &State) { double velocity = State.vz; double h = 0.0; double mass, thrust; // Piecewise functions for F15 thrust curve for (double i = 0.148; i < 3.450; i = i + dt) { mass = State.massInitial - i * State.mdot; if ((i > 0.147) && (i < 0.420)) thrust = 65.165 * i - 2.3921; else if ((i > 0.419) && (i < 3.383)) thrust = 0.8932 * pow(i, 6) - 11.609 * pow(i, 5) + 60.739 * pow(i, 4) - 162.99 * pow(i, 3) + 235.6 * pow(i, 2) - 174.43 * i + 67.17; else if ((i > 3.382) && (i < 3.46)) thrust = -195.78 * i + 675.11; else thrust = 0.0; velocity = (((thrust / mass) + g) * dt) + velocity; h = (((thrust / mass) + g) * dt) + h; } State.z = h + (pow(velocity, 2) / (2.0 * -g)); // starting height State.z = 19.05; State.burnVelocity = velocity; // terminal velocity double burnStartTime = State.burnVelocity / -g; State.simTime = (State.burntime + burnStartTime) * 1000.0; } void vehicleDynamics(Vehicle &State, Vehicle &PrevState) { // Moment of Inertia State.I11 = State.mass * ((1 / 12.0) * pow(State.vehicleHeight, 2) + pow(State.vehicleRadius, 2) / 4.0); State.I22 = State.mass * ((1 / 12.0) * pow(State.vehicleHeight, 2) + pow(State.vehicleRadius, 2) / 4.0); State.I33 = State.mass * 0.5 * pow(State.vehicleRadius, 2); // Idot if (State.time < 0.1) { State.I11dot = 0.0; State.I22dot = 0.0; State.I33dot = 0.0; State.x = 0.0; State.y = 0.0; State.ax = 0.0; State.ay = 0.0; State.az = State.Fz / State.massInitial; } else { State.I11dot = derivative(State.I11, PrevState.I11, State.stepSize); State.I22dot = derivative(State.I22, PrevState.I22, State.stepSize); State.I33dot = derivative(State.I33, PrevState.I33, State.stepSize); // pdot, qdot, rdot State.yawddot = (State.momentX - State.I11dot * PrevState.yawdot + State.I22 * PrevState.pitchdot * PrevState.rolldot - State.I33 * PrevState.pitchdot * PrevState.rolldot) / State.I11; State.pitchddot = (State.momentY - State.I22dot * PrevState.pitchdot - State.I11 * PrevState.rolldot * PrevState.yawdot + State.I33 * PrevState.rolldot * PrevState.yawdot) / State.I22; State.rollddot = (State.momentZ - State.I33dot * PrevState.rolldot + State.I11 * PrevState.pitchdot * PrevState.yawdot - State.I22 * PrevState.pitchdot * PrevState.yawdot) / State.I33; // p, q, r State.yawdot = integral(State.yawddot, PrevState.yawdot, State.stepSize); State.pitchdot = integral(State.pitchddot, PrevState.pitchdot, State.stepSize); State.rolldot = integral(State.rollddot, PrevState.rolldot, State.stepSize); // Euler Angles State.phidot = State.yawdot + (sin(State.pitch) * (State.rolldot * cos(State.yaw) + State.pitchdot * sin(State.yaw))) / cos(State.pitch); State.thetadot = State.pitchdot * cos(State.yaw) - State.rolldot * sin(State.yaw); State.psidot = (State.rolldot * cos(State.yaw) + State.pitchdot * sin(State.yaw)) / cos(State.pitch); State.yaw = integral(State.phidot, PrevState.yaw, State.stepSize); State.pitch = integral(State.thetadot, PrevState.pitch, State.stepSize); State.roll = integral(State.psidot, PrevState.roll, State.stepSize); // ax ay az State.ax = (State.Fx / State.mass); State.ay = (State.Fy / State.mass); State.az = (State.Fz / State.mass); // vx vy vz in Earth frame State.vx = integral(State.ax, PrevState.vx, State.stepSize); State.vy = integral(State.ay, PrevState.vy, State.stepSize); State.vz = integral(State.az, PrevState.vz, State.stepSize); // Xe State.x = integral(State.vx, PrevState.x, State.stepSize); State.y = integral(State.vy, PrevState.y, State.stepSize); State.z = integral(State.vz, PrevState.z, State.stepSize); } } void pidController(Vehicle &State, struct Vehicle &PrevState) { // Make sure we start reacting when we start burning if (State.thrust > 0.01) { State.yError = State.yaw; State.pError = State.pitch; // Integral of Error State.i_yError = integral(State.yError, State.i_yError, State.stepSize); State.i_pError = integral(State.pError, State.i_pError, State.stepSize); // Derivative of Error State.d_yError = derivative(State.yError, PrevState.yError, State.stepSize); State.d_pError = derivative(State.pError, PrevState.pError, State.stepSize); // TVC block properly State.PIDx = (State.Kp * State.yError + State.Ki * State.i_yError + State.Kd * State.d_yError) / State.momentArm; State.PIDy = (State.Kp * State.pError + State.Ki * State.i_pError + State.Kd * State.d_pError) / State.momentArm; } else { State.PIDx = 0.0; State.PIDy = 0.0; } // PID Force Limiter State.PIDx = limit(State.PIDx, State.thrust, -State.thrust); State.PIDy = limit(State.PIDy, State.thrust, -State.thrust); } void TVC(Vehicle &State, Vehicle &PrevState) { if (State.thrust < 0.1) { // Define forces and moments for t = 0 State.Fx = 0.0; State.Fy = 0.0; State.Fz = g * State.massInitial; State.momentX = 0.0; State.momentY = 0.0; State.momentZ = 0.0; } else { // Convert servo position to degrees for comparison to max allowable State.xServoDegs = (180.0 / M_PI) * asin(State.PIDx / State.thrust); State.yServoDegs = (180.0 / M_PI) * asin(State.PIDy / State.thrust); // Limit Servo Position State.xServoDegs = limit(State.xServoDegs, State.maxServo, -State.maxServo); State.yServoDegs = limit(State.yServoDegs, State.maxServo, -State.maxServo); // Servo Rate State.xServoDegsDot = derivative(State.xServoDegs, PrevState.xServoDegs, State.stepSize); State.yServoDegsDot = derivative(State.yServoDegs, PrevState.yServoDegs, State.stepSize); // Limit Servo Rate State.xServoDegsDot = limit(State.xServoDegsDot, State.maxServoRate, -State.maxServoRate); State.yServoDegsDot = limit(State.yServoDegsDot, State.maxServoRate, -State.maxServoRate); // Back to Degrees State.xServoDegs = integral(State.xServoDegsDot, PrevState.xServoDegs, State.stepSize); State.yServoDegs = integral(State.yServoDegsDot, PrevState.yServoDegs, State.stepSize); } } void state2vec(Vehicle &State, Vehicle &PrevState, outVector &stateVector) { int t = State.time; stateVector.x[t] = State.x; stateVector.y[t] = State.y; stateVector.z[t] = State.z; stateVector.vx[t] = State.vx; stateVector.vy[t] = State.vy; stateVector.vz[t] = State.vz; stateVector.ax[t] = State.ax; stateVector.ay[t] = State.ay; stateVector.az[t] = State.az; stateVector.yaw[t] = State.yaw; stateVector.pitch[t] = State.pitch; stateVector.roll[t] = State.roll; stateVector.yawdot[t] = State.yawdot; stateVector.pitchdot[t] = State.pitchdot; stateVector.rolldot[t] = State.rolldot; stateVector.servo1[t] = State.xServoDegs; stateVector.servo2[t] = State.yServoDegs; stateVector.thrustFiring[t] = State.thrustFiring; stateVector.PIDx[t] = State.PIDx; stateVector.PIDy[t] = State.PIDy; stateVector.thrust[t] = State.thrust; } double derivative(double current, double previous, double step) { double dxdt = (current - previous) / (step / 1000.0); return dxdt; } double integral(double currentChange, double prevValue, double dt) { return (currentChange * dt / 1000.0) + prevValue; } double limit(double value, double upr, double lwr) { if (value > upr) value = upr; else if (value < lwr) value = lwr; else value = value; return value; } void getThrust(Vehicle &State) { if ((State.burnElapsed > 0.147) && (State.burnElapsed < 0.420)) { State.thrust = 65.165 * State.burnElapsed - 2.3921; } else if ((State.burnElapsed > 0.419) && (State.burnElapsed < 3.383)) State.thrust = 0.8932 * pow(State.burnElapsed, 6.0) - 11.609 * pow(State.burnElapsed, 5.0) + 60.739 * pow(State.burnElapsed, 4.0) - 162.99 * pow(State.burnElapsed, 3.0) + 235.6 * pow(State.burnElapsed, 2.0) - 174.43 * State.burnElapsed + 67.17; else if ((State.burnElapsed > 3.382) && (State.burnElapsed < 3.46)) { State.thrust = -195.78 * State.burnElapsed + 675.11; } if (State.burnElapsed > 3.45) { State.thrustFiring = 2; State.thrust = 0.0; } }