1
0
mirror of https://gitlab.com/lander-team/lander-cpp.git synced 2025-06-16 15:17:23 +00:00

383 lines
12 KiB
C++

#include "sVars.h"
void burnStartTimeCalc(struct sVars &);
void thrustSelection(struct sVars &, int t);
void lqrCalc(struct sVars &);
void TVC(struct sVars &);
void vehicleDynamics(struct sVars &, int t);
void write2CSV(struct sVars &, std::fstream &outfile, int t);
double derivative(double x2, double x1, double dt);
double integral(double x2, double x1, double dt);
// Any parameters that are constants should be declared here instead of buried
// in code
double const dt = 0.001;
double const g = -9.81;
void sim(struct sVars &Vars) {
// defining a few random values here cause I'm lazy
Vars.burnElapsed = 2000;
Vars.mass = Vars.massInitial;
Vars.thrust_prev = 0;
burnStartTimeCalc(Vars);
// Deleting any previous output file
if (remove("simOut.csv") != 0)
perror("Error deleting file");
else
puts("File successfully deleted");
// Define and open output file "simOut.csv"
std::fstream outfile;
outfile.open("simOut.csv", std::ios::app);
// Output file header. These are the variables that we output - useful for
// debugging
outfile
<< "t, x, y, z, vx, vy, vz, ax, ay, az, yaw, pitch, roll, yawdot, "
"pitchdot, rolldot, yawddot, pitchddot, rollddot, I11, I22, I33, "
"I11dot, I22dot, I33dot, Servo1, Servo2, m, thrust, burnElapsed, Fz, "
"LQRx, LQRy"
<< std::endl;
// Start Sim
for (int t = 0; t < Vars.simTime; t++) {
thrustSelection(Vars, t);
lqrCalc(Vars);
TVC(Vars);
vehicleDynamics(Vars, t);
write2CSV(Vars, outfile,
t); // TODO: Need to append to memory instead of writing each step
}
outfile.close();
}
void burnStartTimeCalc(struct sVars &Vars) {
double velocity = Vars.vz;
double h = 0;
double a, j, mass, thrust;
// Piecewise functions for F15 thrust curve
for (double i = 0.148; i < 3.450; i = i + dt) {
mass = Vars.massInitial - i * Vars.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;
velocity = (((thrust / mass) + g) * dt) + velocity;
h = velocity * dt + h;
}
Vars.z = h + (pow(velocity, 2) / (2 * -g)); // starting height
Vars.burnVelocity = velocity; // terminal velocity
double burnStartTime = Vars.burnVelocity / -g;
Vars.simTime = (Vars.burntime + burnStartTime) * 1000;
}
void thrustSelection(struct sVars &Vars, int t) {
if (Vars.burnElapsed != 2000) {
// determine where in the thrust curve we're at based on elapsed burn time
// as well as current mass
Vars.burnElapsed = (t - Vars.burnStart) / 1000;
Vars.mass = Vars.massInitial - (Vars.mdot * Vars.burnElapsed);
}
else if (abs(Vars.burnVelocity - Vars.vz) < .001) {
// Start burn
Vars.burnStart = t;
Vars.burnElapsed = 0;
}
else // TODO: Make this not arbitrary
Vars.burnElapsed = 2000; // arbitrary number to ensure we don't burn
if ((Vars.burnElapsed > 0.147) && (Vars.burnElapsed < 0.420))
Vars.thrust = 65.165 * Vars.burnElapsed - 2.3921;
else if ((Vars.burnElapsed > 0.419) && (Vars.burnElapsed < 3.383))
Vars.thrust =
0.8932 * pow(Vars.burnElapsed, 6) - 11.609 * pow(Vars.burnElapsed, 5) +
60.739 * pow(Vars.burnElapsed, 4) - 162.99 * pow(Vars.burnElapsed, 3) +
235.6 * pow(Vars.burnElapsed, 2) - 174.43 * Vars.burnElapsed + 67.17;
else if ((Vars.burnElapsed > 3.382) && (Vars.burnElapsed < 3.46))
Vars.thrust = -195.78 * Vars.burnElapsed + 675.11;
}
void lqrCalc(struct sVars &Vars) {
Vars.I11 = Vars.mass * ((1 / 12) * pow(Vars.vehicleHeight, 2) +
pow(Vars.vehicleRadius, 2) / 4);
Vars.I22 = Vars.mass * ((1 / 12) * pow(Vars.vehicleHeight, 2) +
pow(Vars.vehicleRadius, 2) / 4);
Vars.I33 = Vars.mass * 0.5 * pow(Vars.vehicleRadius, 2);
// Paste in Values from gainCalc.m
double K11 = 39.54316;
double K12 = 0.00000;
double K13 = -0.00000;
double K14 = 39.55769;
double K15 = 0.00000;
double K16 = 0.00000;
double K21 = 0.00000;
double K22 = 39.54316;
double K23 = 0.00000;
double K24 = 0.00000;
double K25 = 39.55769;
double K26 = 0.00000;
double K31 = 0.00000;
double K32 = 0.00000;
double K33 = 39.54316;
double K34 = 0.00000;
double K35 = 0.00000;
double K36 = 39.54394;
// changing gain exponent drastically changes results of LQR
double gain = 0.25 * pow(10, -4);
// Matrix Multiply K with [YPR/2; w123] column vector and divide by moment arm
Vars.LQRx =
gain *
((K12 * Vars.pitch) / 2 + K15 * Vars.pitchdot + (K13 * Vars.roll) / 2 +
K16 * Vars.rolldot + (K11 * Vars.yaw) / 2 + K14 * Vars.yawdot) /
-Vars.momentArm;
Vars.LQRy =
gain *
((K22 * Vars.pitch) / 2 + K25 * Vars.pitchdot + (K23 * Vars.roll) / 2 +
K26 * Vars.rolldot + (K21 * Vars.yaw) / 2 + K24 * Vars.yawdot) /
-Vars.momentArm;
// LQR Force limiter X
if (Vars.LQRx > Vars.thrust)
Vars.LQRx = Vars.thrust;
else if (Vars.LQRx < -1 * Vars.thrust)
Vars.LQRx = -1 * Vars.thrust;
// LQR Force limiter Y
if (Vars.LQRy > Vars.thrust)
Vars.LQRy = Vars.thrust;
else if (Vars.LQRy < -1 * Vars.thrust)
Vars.LQRy = -1 * Vars.thrust;
}
void TVC(struct sVars &Vars) {
if (Vars.thrust < 1) {
// Define forces and moments for t = 0
Vars.Fx = 0;
Vars.Fy = 0;
Vars.Fz = g * Vars.massInitial;
Vars.momentX = 0;
Vars.momentY = 0;
Vars.momentZ = 0;
} else {
// Convert servo position to degrees for comparison to max allowable
Vars.xServoDegs = (180 / M_PI) * asin(Vars.LQRx / Vars.thrust);
// Servo position limiter
if (Vars.xServoDegs > Vars.maxServo)
Vars.xServoDegs = Vars.maxServo;
else if (Vars.xServoDegs < -1 * Vars.maxServo)
Vars.xServoDegs = -1 * Vars.maxServo;
// Convert servo position to degrees for comparison to max allowable
Vars.yServoDegs = (180 / M_PI) * asin(Vars.LQRy / Vars.thrust);
// Servo position limiter
if (Vars.yServoDegs > Vars.maxServo)
Vars.yServoDegs = Vars.maxServo;
else if (Vars.yServoDegs < -1 * Vars.maxServo)
Vars.yServoDegs = -1 * Vars.maxServo;
// Vector math to aqcuire thrust vector components
Vars.Fx = Vars.thrust * sin(Vars.xServoDegs * (M_PI / 180));
Vars.Fy = Vars.thrust * sin(Vars.yServoDegs * (M_PI / 180));
Vars.Fz = sqrt(pow(Vars.thrust, 2) - (pow(Vars.Fx, 2) + pow(Vars.Fy, 2))) +
(Vars.mass * g);
// Calculate moment created by Fx and Fy
Vars.momentX = Vars.Fx * Vars.momentArm;
Vars.momentY = Vars.Fy * Vars.momentArm;
Vars.momentZ = 0;
}
}
void vehicleDynamics(struct sVars &Vars, int t) {
// Idot
if (t < 1) { // TODO: Initial conditions should be set at sim start
Vars.I11dot = 0;
Vars.I22dot = 0;
Vars.I33dot = 0;
} else {
Vars.I11dot = derivative(Vars.I11, Vars.I11prev, Vars.stepSize);
Vars.I22dot = derivative(Vars.I22, Vars.I22prev, Vars.stepSize);
Vars.I33dot = derivative(Vars.I33, Vars.I33prev, Vars.stepSize);
}
// pdot, qdot, rdot
Vars.yawddot = (Vars.momentX - Vars.I11dot * Vars.yawdot +
Vars.I22 * Vars.pitchdot * Vars.rolldot -
Vars.I33 * Vars.pitchdot * Vars.rolldot) /
Vars.I11;
Vars.pitchddot = (Vars.momentY - Vars.I22dot * Vars.pitchdot -
Vars.I11 * Vars.rolldot * Vars.yawdot +
Vars.I33 * Vars.rolldot * Vars.yawdot) /
Vars.I22;
Vars.rollddot = (Vars.momentZ - Vars.I33dot * Vars.rolldot +
Vars.I11 * Vars.pitchdot * Vars.yawdot -
Vars.I22 * Vars.pitchdot * Vars.yawdot) /
Vars.I33;
if (t < 1) { // TODO: Initial conditions should be set at sim start
Vars.x = 0;
Vars.y = 0;
Vars.ax = 0;
Vars.ay = 0;
Vars.az = Vars.Fz / Vars.massInitial;
}
else {
// p, q, r
Vars.yawdot = integral(Vars.yawddot, Vars.yawdotPrev, Vars.stepSize);
Vars.pitchdot = integral(Vars.pitchddot, Vars.pitchdotPrev, Vars.stepSize);
Vars.rolldot = integral(Vars.rollddot, Vars.rolldotPrev, Vars.stepSize);
// ax ay az
Vars.ax = (Vars.Fx / Vars.mass) +
(Vars.pitchdot * Vars.vz - Vars.rolldot * Vars.vy);
Vars.ay = (Vars.Fy / Vars.mass) +
(Vars.rolldot * Vars.vx - Vars.vz * Vars.yawdot);
Vars.az = (Vars.Fz / Vars.mass) +
(Vars.vy * Vars.yawdot - Vars.pitchdot * Vars.vx);
// vx vy vz in Body frame
Vars.vx = integral(Vars.ax, Vars.vxPrev, Vars.stepSize);
Vars.vy = integral(Vars.ay, Vars.vyPrev, Vars.stepSize);
Vars.vz = integral(Vars.az, Vars.vzPrev, Vars.stepSize);
// Xe
Vars.x = integral(Vars.vx, Vars.xPrev, Vars.stepSize);
Vars.y = integral(Vars.vy, Vars.yPrev, Vars.stepSize);
Vars.z = integral(Vars.vz, Vars.zPrev, Vars.stepSize);
// Euler Angles
Vars.phidot = Vars.yawdot + (Vars.pitchdot * sin(Vars.yaw) +
Vars.rolldot * cos(Vars.yaw)) *
(sin(Vars.pitch) / cos(Vars.pitch));
Vars.thetadot =
Vars.pitchdot * cos(Vars.yaw) - Vars.rolldot * sin(Vars.pitch);
Vars.psidot =
(Vars.pitchdot * sin(Vars.yaw) + Vars.rolldot * cos(Vars.yaw)) /
cos(Vars.pitch);
Vars.yaw = integral(Vars.phidot, Vars.yawPrev, Vars.stepSize);
Vars.pitch = integral(Vars.thetadot, Vars.pitchPrev, Vars.stepSize);
Vars.roll = integral(Vars.psidot, Vars.rollPrev, Vars.stepSize);
}
// TODO: Maybe we should just have a `Vars` for the last time step and at the
// end of each time step make a copy of it
// TODO: Delete, section not needed
// Set "prev" values for next timestep
Vars.I11prev = Vars.I11;
Vars.I22prev = Vars.I22;
Vars.I33prev = Vars.I33;
Vars.yawPrev = Vars.yaw;
Vars.pitchPrev = Vars.pitch;
Vars.rollPrev = Vars.roll;
Vars.yawdotPrev = Vars.yawdot;
Vars.pitchdotPrev = Vars.pitchdot;
Vars.rolldotPrev = Vars.rolldot;
Vars.yawddotPrev = Vars.yawddot;
Vars.pitchddotPrev = Vars.pitchddot;
Vars.rollddotPrev = Vars.rollddot;
Vars.axPrev = Vars.ax;
Vars.ayPrev = Vars.ay;
Vars.azPrev = Vars.az;
Vars.vxPrev = Vars.vx;
Vars.vyPrev = Vars.vy;
Vars.vzPrev = Vars.vz;
Vars.xPrev = Vars.x;
Vars.yPrev = Vars.y;
Vars.zPrev = Vars.z;
}
void write2CSV(struct sVars &Vars, std::fstream &outfile, int t) {
// writing to output file
outfile << t << ", ";
outfile << Vars.x << ", ";
outfile << Vars.y << ", ";
outfile << Vars.z << ", ";
outfile << Vars.vx << ", ";
outfile << Vars.vy << ", ";
outfile << Vars.vz << ", ";
outfile << Vars.ax << ", ";
outfile << Vars.ay << ", ";
outfile << Vars.az << ", ";
outfile << Vars.yaw * 180 / M_PI << ", ";
outfile << Vars.pitch * 180 / M_PI << ", ";
outfile << Vars.roll * 180 / M_PI << ", ";
outfile << Vars.yawdot * 180 / M_PI << ", ";
outfile << Vars.pitchdot * 180 / M_PI << ", ";
outfile << Vars.rolldot * 180 / M_PI << ", ";
outfile << Vars.yawddot * 180 / M_PI << ", ";
outfile << Vars.pitchddot * 180 / M_PI << ", ";
outfile << Vars.rollddot * 180 / M_PI << ", ";
outfile << Vars.I11 << ", ";
outfile << Vars.I22 << ", ";
outfile << Vars.I33 << ", ";
outfile << Vars.I11dot << ", ";
outfile << Vars.I22dot << ", ";
outfile << Vars.I33dot << ", ";
outfile << Vars.xServoDegs << ", ";
outfile << Vars.yServoDegs << ", ";
outfile << Vars.mass << ", ";
outfile << Vars.thrust << ", ";
outfile << Vars.burnElapsed << ", ";
outfile << Vars.Fz << ", ";
outfile << Vars.LQRx << ", ";
outfile << Vars.LQRy << std::endl;
}
double derivative(double x2, double x1, double dt) {
// TODO: is 1000 arbitrary?
double dxdt = (x2 - x1) / (dt / 1000);
return dxdt;
}
double integral(double x, double y, double dt) {
double integ = (x * dt / 1000) + y;
return integ;
}