mirror of
https://gitlab.com/lander-team/lander-cpp.git
synced 2025-06-16 15:17:23 +00:00
initial commit
This commit is contained in:
parent
e2ef9a7232
commit
44d0db8bfd
6
.vscode/settings.json
vendored
Normal file
6
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"files.associations": {
|
||||||
|
"array": "cpp",
|
||||||
|
"iostream": "cpp"
|
||||||
|
}
|
||||||
|
}
|
52
.vscode/tasks.json
vendored
Normal file
52
.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"type": "cppbuild",
|
||||||
|
"label": "Debug",
|
||||||
|
"command": "C:\\Program Files\\mingw-w64\\x86_64-8.1.0-posix-seh-rt_v6-rev0\\mingw64\\bin\\g++.exe",
|
||||||
|
"args": [
|
||||||
|
"-g",
|
||||||
|
"${workspaceFolder}\\src\\*.cpp",
|
||||||
|
"-o",
|
||||||
|
"${workspaceFolder}\\build\\debug\\${fileBasenameNoExtension}.exe",
|
||||||
|
"-I",
|
||||||
|
"${workspaceFolder}\\include",
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"cwd": "${fileDirname}"
|
||||||
|
},
|
||||||
|
"problemMatcher": [
|
||||||
|
"$gcc"
|
||||||
|
],
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
},
|
||||||
|
"detail": "compiler: \"C:\\Program Files\\mingw-w64\\x86_64-8.1.0-posix-seh-rt_v6-rev0\\mingw64\\bin\\g++.exe\""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "cppbuild",
|
||||||
|
"label": "Release",
|
||||||
|
"command": "C:\\Program Files\\mingw-w64\\x86_64-8.1.0-posix-seh-rt_v6-rev0\\mingw64\\bin\\g++.exe",
|
||||||
|
"args": [
|
||||||
|
"${workspaceFolder}\\src\\*.cpp",
|
||||||
|
"-o",
|
||||||
|
"${workspaceFolder}\\build\\release\\${fileBasenameNoExtension}.exe",
|
||||||
|
"-I",
|
||||||
|
"${workspaceFolder}\\include",
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"cwd": "${fileDirname}"
|
||||||
|
},
|
||||||
|
"problemMatcher": [
|
||||||
|
"$gcc"
|
||||||
|
],
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
},
|
||||||
|
"detail": "compiler: \"C:\\Program Files\\mingw-w64\\x86_64-8.1.0-posix-seh-rt_v6-rev0\\mingw64\\bin\\g++.exe\""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
30
build/debug/LQR.m
Normal file
30
build/debug/LQR.m
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
clear all; clc;
|
||||||
|
|
||||||
|
syms R11 R22 R33
|
||||||
|
R = [R11 0 0;
|
||||||
|
0 R22 0;
|
||||||
|
0 0 R33];
|
||||||
|
|
||||||
|
syms I33
|
||||||
|
Q = eye(6) * I33;
|
||||||
|
|
||||||
|
syms F11 F22 F33
|
||||||
|
F = [F11 0 0;
|
||||||
|
0 F22 0
|
||||||
|
0 0 F33];
|
||||||
|
|
||||||
|
syms G13 G31
|
||||||
|
G = [0 0 G13;
|
||||||
|
0 0 0;
|
||||||
|
G31 0 0];
|
||||||
|
|
||||||
|
syms I11 I22 d
|
||||||
|
I = [I11 0 0;
|
||||||
|
0 I22 0;
|
||||||
|
0 0 I33];
|
||||||
|
|
||||||
|
A = [zeros(3,3), d * eye(3); F, G];
|
||||||
|
B = [zeros(3,3); inv(I)];
|
||||||
|
P = [-Q, -A'] * pinv([A, -B*inv(R)*B']);
|
||||||
|
|
||||||
|
K = simplify((R^-1) * B' * P)
|
BIN
build/debug/main.exe
Normal file
BIN
build/debug/main.exe
Normal file
Binary file not shown.
4318
build/debug/simOut.csv
Normal file
4318
build/debug/simOut.csv
Normal file
File diff suppressed because it is too large
Load Diff
81
build/debug/simPlot.m
Normal file
81
build/debug/simPlot.m
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
clear all; close all; clc;
|
||||||
|
|
||||||
|
% Read data and transfer to variables
|
||||||
|
T = readmatrix('simOut.csv');
|
||||||
|
t = T(:, 1);
|
||||||
|
x = T(:, 2);
|
||||||
|
y = T(:, 3);
|
||||||
|
z = T(:, 4);
|
||||||
|
vx = T(:, 5);
|
||||||
|
vy = T(:, 6);
|
||||||
|
vz = T(:, 7);
|
||||||
|
ax = T(:, 8);
|
||||||
|
ay = T(:, 9);
|
||||||
|
az = T(:, 10);
|
||||||
|
yaw = T(:, 11);
|
||||||
|
pitch = T(:, 12);
|
||||||
|
roll = T(:, 13);
|
||||||
|
yawdot = T(:, 14);
|
||||||
|
pitchdot = T(:, 15);
|
||||||
|
rolldot = T(:, 16);
|
||||||
|
Servo1 = T(:, 17);
|
||||||
|
Servo2 = T(:, 18);
|
||||||
|
m = T(:, 19);
|
||||||
|
thrust = T(:, 20);
|
||||||
|
|
||||||
|
% Acceleration
|
||||||
|
subplot(3, 1, 1)
|
||||||
|
plot(t, az)
|
||||||
|
title('Acceleration vs Time')
|
||||||
|
xlabel('Time (s)')
|
||||||
|
ylabel('Acceleration (g''s)')
|
||||||
|
|
||||||
|
% Velocity
|
||||||
|
subplot(3, 1, 2)
|
||||||
|
plot(t, vz)
|
||||||
|
title('Velocity vs Time')
|
||||||
|
xlabel('Time (s)')
|
||||||
|
ylabel('Velocity (m/s)')
|
||||||
|
|
||||||
|
% Altitude
|
||||||
|
subplot(3, 1, 3)
|
||||||
|
plot(t, z)
|
||||||
|
title('Altitude vs Time')
|
||||||
|
xlabel('Time (s)')
|
||||||
|
ylabel('Altitude (m)')
|
||||||
|
ylim([0 z(1)+5])
|
||||||
|
saveas(gcf,'outputs/Accel-Vel-Alt vs Time.png')
|
||||||
|
|
||||||
|
figure(2)
|
||||||
|
|
||||||
|
% Euler Angles
|
||||||
|
subplot(2, 1, 1)
|
||||||
|
plot(t, yaw, pitch, roll)
|
||||||
|
title('Euler Angles vs Time')
|
||||||
|
xlabel('Time (ms)')
|
||||||
|
ylabel('Euler Angles (deg)')
|
||||||
|
|
||||||
|
% Angular Velocity
|
||||||
|
subplot(2, 1, 2)
|
||||||
|
plot(t, yawdot, pitchdot, rolldot)
|
||||||
|
title('Angular Velocity vs Time')
|
||||||
|
xlabel('Time (ms)')
|
||||||
|
ylabel('Angular Velocity (deg/s)')
|
||||||
|
saveas(gcf,'outputs/Euler Angles vs Time.png')
|
||||||
|
|
||||||
|
figure(3)
|
||||||
|
|
||||||
|
% Servo 1 Position
|
||||||
|
subplot(2, 1, 1)
|
||||||
|
plot(t, Servo1)
|
||||||
|
title('Servo 1 Position vs Time')
|
||||||
|
xlabel('Time (ms)')
|
||||||
|
ylabel('Servo 1 Position (rad)')
|
||||||
|
|
||||||
|
% Servo 2 Position
|
||||||
|
subplot(2, 1, 2)
|
||||||
|
plot(t, Servo2)
|
||||||
|
title('Servo 2 Position vs Time')
|
||||||
|
xlabel('Time (ms)')
|
||||||
|
ylabel('Servo 2 Position (rad)')
|
||||||
|
saveas(gcf,'outputs/Servo Position vs Time.png')
|
30
build/release/LQR.m
Normal file
30
build/release/LQR.m
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
clear all; clc;
|
||||||
|
|
||||||
|
syms R11 R22 R33
|
||||||
|
R = [R11 0 0;
|
||||||
|
0 R22 0;
|
||||||
|
0 0 R33];
|
||||||
|
|
||||||
|
syms I33
|
||||||
|
Q = eye(6) * I33;
|
||||||
|
|
||||||
|
syms F11 F22 F33
|
||||||
|
F = [F11 0 0;
|
||||||
|
0 F22 0
|
||||||
|
0 0 F33];
|
||||||
|
|
||||||
|
syms G13 G31
|
||||||
|
G = [0 0 G13;
|
||||||
|
0 0 0;
|
||||||
|
G31 0 0];
|
||||||
|
|
||||||
|
syms I11 I22 d
|
||||||
|
I = [I11 0 0;
|
||||||
|
0 I22 0;
|
||||||
|
0 0 I33];
|
||||||
|
|
||||||
|
A = [zeros(3,3), d * eye(3); F, G];
|
||||||
|
B = [zeros(3,3); inv(I)];
|
||||||
|
P = [-Q, -A'] * pinv([A, -B*inv(R)*B']);
|
||||||
|
|
||||||
|
K = simplify((R^-1) * B' * P)
|
BIN
build/release/main.exe
Normal file
BIN
build/release/main.exe
Normal file
Binary file not shown.
81
build/release/simPlot.m
Normal file
81
build/release/simPlot.m
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
clear all; close all; clc;
|
||||||
|
|
||||||
|
% Read data and transfer to variables
|
||||||
|
T = readmatrix('simOut.csv');
|
||||||
|
t = T(:, 1);
|
||||||
|
x = T(:, 2);
|
||||||
|
y = T(:, 3);
|
||||||
|
z = T(:, 4);
|
||||||
|
vx = T(:, 5);
|
||||||
|
vy = T(:, 6);
|
||||||
|
vz = T(:, 7);
|
||||||
|
ax = T(:, 8);
|
||||||
|
ay = T(:, 9);
|
||||||
|
az = T(:, 10);
|
||||||
|
yaw = T(:, 11);
|
||||||
|
pitch = T(:, 12);
|
||||||
|
roll = T(:, 13);
|
||||||
|
yawdot = T(:, 14);
|
||||||
|
pitchdot = T(:, 15);
|
||||||
|
rolldot = T(:, 16);
|
||||||
|
Servo1 = T(:, 17);
|
||||||
|
Servo2 = T(:, 18);
|
||||||
|
m = T(:, 19);
|
||||||
|
thrust = T(:, 20);
|
||||||
|
|
||||||
|
% Acceleration
|
||||||
|
subplot(3, 1, 1)
|
||||||
|
plot(t, az)
|
||||||
|
title('Acceleration vs Time')
|
||||||
|
xlabel('Time (s)')
|
||||||
|
ylabel('Acceleration (g''s)')
|
||||||
|
|
||||||
|
% Velocity
|
||||||
|
subplot(3, 1, 2)
|
||||||
|
plot(t, vz)
|
||||||
|
title('Velocity vs Time')
|
||||||
|
xlabel('Time (s)')
|
||||||
|
ylabel('Velocity (m/s)')
|
||||||
|
|
||||||
|
% Altitude
|
||||||
|
subplot(3, 1, 3)
|
||||||
|
plot(t, z)
|
||||||
|
title('Altitude vs Time')
|
||||||
|
xlabel('Time (s)')
|
||||||
|
ylabel('Altitude (m)')
|
||||||
|
ylim([0 z(1)+5])
|
||||||
|
saveas(gcf,'outputs/Accel-Vel-Alt vs Time.png')
|
||||||
|
|
||||||
|
figure(2)
|
||||||
|
|
||||||
|
% Euler Angles
|
||||||
|
subplot(2, 1, 1)
|
||||||
|
plot(t, yaw, pitch, roll)
|
||||||
|
title('Euler Angles vs Time')
|
||||||
|
xlabel('Time (ms)')
|
||||||
|
ylabel('Euler Angles (deg)')
|
||||||
|
|
||||||
|
% Angular Velocity
|
||||||
|
subplot(2, 1, 2)
|
||||||
|
plot(t, yawdot, pitchdot, rolldot)
|
||||||
|
title('Angular Velocity vs Time')
|
||||||
|
xlabel('Time (ms)')
|
||||||
|
ylabel('Angular Velocity (deg/s)')
|
||||||
|
saveas(gcf,'outputs/Euler Angles vs Time.png')
|
||||||
|
|
||||||
|
figure(3)
|
||||||
|
|
||||||
|
% Servo 1 Position
|
||||||
|
subplot(2, 1, 1)
|
||||||
|
plot(t, Servo1)
|
||||||
|
title('Servo 1 Position vs Time')
|
||||||
|
xlabel('Time (ms)')
|
||||||
|
ylabel('Servo 1 Position (rad)')
|
||||||
|
|
||||||
|
% Servo 2 Position
|
||||||
|
subplot(2, 1, 2)
|
||||||
|
plot(t, Servo2)
|
||||||
|
title('Servo 2 Position vs Time')
|
||||||
|
xlabel('Time (ms)')
|
||||||
|
ylabel('Servo 2 Position (rad)')
|
||||||
|
saveas(gcf,'outputs/Servo Position vs Time.png')
|
70
include/sVars.h
Normal file
70
include/sVars.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#include <array>
|
||||||
|
|
||||||
|
#ifndef SVARS_H
|
||||||
|
#define SVARS_H
|
||||||
|
|
||||||
|
struct sVars
|
||||||
|
{
|
||||||
|
double x, y, z;
|
||||||
|
double xPrev, yPrev, zPrev;
|
||||||
|
double vx, vy, vz;
|
||||||
|
double vxPrev, vyPrev, vzPrev;
|
||||||
|
double vxBody, vyBody, vzBody;
|
||||||
|
double ax, ay, az, axPrev, ayPrev, azPrev;
|
||||||
|
|
||||||
|
double yaw, pitch, roll;
|
||||||
|
double phidot, thetadot, psidot;
|
||||||
|
double yawPrev, pitchPrev, rollPrev;
|
||||||
|
double yawdot, pitchdot, rolldot;
|
||||||
|
double yawdotPrev, pitchdotPrev, rolldotPrev;
|
||||||
|
double yawddot, pitchddot, rollddot;
|
||||||
|
double yawddotPrev, pitchddotPrev, rollddotPrev;
|
||||||
|
|
||||||
|
double m, m0, mp, mb, mdot;
|
||||||
|
double vehicleHeight, vehicleRadius;
|
||||||
|
|
||||||
|
double tb;
|
||||||
|
double vb;
|
||||||
|
double thrust, thrust_prev, burnElapsed, burnStart;
|
||||||
|
double LQRx, LQRy, Fx, Fy, Fz;
|
||||||
|
double momentX, momentY, momentZ;
|
||||||
|
|
||||||
|
double I11, I22, I33;
|
||||||
|
double I11prev, I22prev, I33prev;
|
||||||
|
double I11dot, I22dot, I33dot;
|
||||||
|
|
||||||
|
int maxServo;
|
||||||
|
double xServoDegs, yServoDegs;
|
||||||
|
|
||||||
|
double simTime;
|
||||||
|
int stepSize;
|
||||||
|
|
||||||
|
std::array<std::array<double, 2>, 26> thrustCurve = { { {0.148, 7.638},
|
||||||
|
{0.228, 12.253},
|
||||||
|
{0.294, 16.391},
|
||||||
|
{0.353, 20.210},
|
||||||
|
{0.382, 22.756},
|
||||||
|
{0.419, 25.260},
|
||||||
|
{0.477, 23.074},
|
||||||
|
{0.520, 20.845},
|
||||||
|
{0.593, 19.093},
|
||||||
|
{0.688, 17.500},
|
||||||
|
{0.855, 16.225},
|
||||||
|
{1.037, 15.427},
|
||||||
|
{1.205, 14.948},
|
||||||
|
{1.423, 14.627},
|
||||||
|
{1.452, 15.741},
|
||||||
|
{1.503, 14.785},
|
||||||
|
{1.736, 14.623},
|
||||||
|
{1.955, 14.303},
|
||||||
|
{2.210, 14.141},
|
||||||
|
{2.494, 13.819},
|
||||||
|
{2.763, 13.338},
|
||||||
|
{3.120, 13.334},
|
||||||
|
{3.382, 13.013},
|
||||||
|
{3.404, 9.352},
|
||||||
|
{3.418, 4.895},
|
||||||
|
{3.450, 0.000}} };
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
10
include/sim.h
Normal file
10
include/sim.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#include "sVars.h"
|
||||||
|
|
||||||
|
void burnStartTimeCalc(struct sVars&, double g);
|
||||||
|
void thrustSelection(struct sVars&, int t);
|
||||||
|
void lqrCalc(struct sVars&);
|
||||||
|
void TVC(struct sVars&, double g);
|
||||||
|
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);
|
48
src/main.cpp
Normal file
48
src/main.cpp
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#include "sim.h"
|
||||||
|
#include "sVars.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
void sim(struct sVars &);
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
sVars Vars;
|
||||||
|
|
||||||
|
// Initial Velocity
|
||||||
|
Vars.vx = 0; // [m/s]
|
||||||
|
Vars.vy = 0; // [m/s]
|
||||||
|
Vars.vz = 0; // [m/s]
|
||||||
|
|
||||||
|
// Initial YPR
|
||||||
|
Vars.yaw = 0; // [rad]
|
||||||
|
Vars.pitch = 0; // [rad]
|
||||||
|
Vars.roll = 0; // [rad]
|
||||||
|
|
||||||
|
// Initial YPRdot
|
||||||
|
Vars.yawdot = 0; // [rad/s]
|
||||||
|
Vars.pitchdot = 0; // [rad/s]
|
||||||
|
Vars.rolldot = 0; // [rad/s]
|
||||||
|
|
||||||
|
// Servo Limitation
|
||||||
|
Vars.maxServo = 0; // [degs]
|
||||||
|
|
||||||
|
// Vehicle Properties
|
||||||
|
Vars.m0 = 1.2; // [kg]
|
||||||
|
Vars.vehicleHeight = 0.5318; // [m]
|
||||||
|
Vars.vehicleRadius = 0.05105; // [m]
|
||||||
|
|
||||||
|
// Sim Step Size
|
||||||
|
Vars.stepSize = 1; // [ms]
|
||||||
|
|
||||||
|
// Other Properties
|
||||||
|
Vars.mp = 0.06; // [kg]
|
||||||
|
Vars.mb = Vars.m0 - Vars.mp; // [kg]
|
||||||
|
Vars.tb = Vars.thrustCurve[25][0] - Vars.thrustCurve[0][0]; // [s]
|
||||||
|
Vars.mdot = Vars.mp / Vars.tb; // [kg/s]
|
||||||
|
|
||||||
|
sim(Vars);
|
||||||
|
|
||||||
|
std::cout << "Finished";
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
403
src/sim.cpp
Normal file
403
src/sim.cpp
Normal file
@ -0,0 +1,403 @@
|
|||||||
|
#include "sim.h"
|
||||||
|
#include <cmath>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
void sim(struct sVars &Vars)
|
||||||
|
{
|
||||||
|
double g = -9.81;
|
||||||
|
|
||||||
|
// defining a few random values here cause I'm lazy
|
||||||
|
Vars.burnElapsed = 2000;
|
||||||
|
Vars.m = Vars.m0;
|
||||||
|
Vars.thrust_prev = 0;
|
||||||
|
|
||||||
|
burnStartTimeCalc(Vars, g);
|
||||||
|
|
||||||
|
// 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, 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, g);
|
||||||
|
vehicleDynamics(Vars, t);
|
||||||
|
write2CSV(Vars, outfile, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
outfile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void burnStartTimeCalc(struct sVars &Vars, double g)
|
||||||
|
{
|
||||||
|
double v_prev = Vars.vz;
|
||||||
|
double h_prev = 0;
|
||||||
|
double dt, a, v, h;
|
||||||
|
|
||||||
|
for (int i = 0; i < 25; i++)
|
||||||
|
{
|
||||||
|
// Integral of thrust curve
|
||||||
|
if (i < 25)
|
||||||
|
{
|
||||||
|
dt = Vars.thrustCurve[i + 1][0] - Vars.thrustCurve[i][0];
|
||||||
|
a = (Vars.thrustCurve[i][1] /
|
||||||
|
(Vars.m0 - Vars.mdot * Vars.thrustCurve[i + 1][0]) +
|
||||||
|
g);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dt = 0;
|
||||||
|
a = (Vars.thrustCurve[i][1] / Vars.mb) + g;
|
||||||
|
}
|
||||||
|
|
||||||
|
v = a * dt + v_prev;
|
||||||
|
v_prev = v;
|
||||||
|
h = v * dt + h_prev;
|
||||||
|
h_prev = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
double hb = h; // height that we want to start our burn at
|
||||||
|
double hf =
|
||||||
|
(v * v) / (2 * -g); // amount of height that we need to be in freefall in
|
||||||
|
// order to reach terminal velocity
|
||||||
|
Vars.z = hb + hf; // starting height
|
||||||
|
Vars.vb = v; // terminal velocity
|
||||||
|
|
||||||
|
double burnStartTime = Vars.vb / -g;
|
||||||
|
Vars.simTime = (Vars.tb + burnStartTime) * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
void thrustSelection(struct sVars &Vars, int t)
|
||||||
|
{
|
||||||
|
double tol = 0.001; // 0.001 seems to be a nice tolerance
|
||||||
|
|
||||||
|
// Check to see if current velocity is close to the F15's total velocity
|
||||||
|
bool b_burnStart = (Vars.vb < (1 + tol) * Vars.vz * -1) &
|
||||||
|
(Vars.vb > (1 - tol) * Vars.vz * -1);
|
||||||
|
|
||||||
|
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.m = Vars.m0 - (Vars.mdot * Vars.burnElapsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (b_burnStart)
|
||||||
|
{
|
||||||
|
// Start burn
|
||||||
|
Vars.burnStart = t;
|
||||||
|
Vars.burnElapsed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
Vars.burnElapsed =
|
||||||
|
2000; // 2000 just an arbitrary number to make sure we don't burn
|
||||||
|
|
||||||
|
bool b_thrustSelect;
|
||||||
|
|
||||||
|
for (int i = 0; i < 25; i++)
|
||||||
|
{
|
||||||
|
// Compare elapsed burn time to each time entry in the thrust curve
|
||||||
|
b_thrustSelect = (Vars.burnElapsed < (1 + tol) * Vars.thrustCurve[i][0]) &
|
||||||
|
(Vars.burnElapsed > (1 - tol) * Vars.thrustCurve[i][0]);
|
||||||
|
|
||||||
|
if (b_thrustSelect)
|
||||||
|
{
|
||||||
|
// Choose thrust associated with time entry that elapsed burn time was
|
||||||
|
// compared to above
|
||||||
|
Vars.thrust = Vars.thrustCurve[i][1];
|
||||||
|
Vars.thrust_prev = Vars.thrustCurve[i][1];
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
// latch
|
||||||
|
Vars.thrust = Vars.thrust_prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void lqrCalc(struct sVars &Vars)
|
||||||
|
{
|
||||||
|
Vars.I11 = Vars.m * ((1 / 12) * pow(Vars.vehicleHeight, 2) +
|
||||||
|
pow(Vars.vehicleRadius, 2) / 4);
|
||||||
|
Vars.I22 = Vars.m * ((1 / 12) * pow(Vars.vehicleHeight, 2) +
|
||||||
|
pow(Vars.vehicleRadius, 2) / 4);
|
||||||
|
Vars.I33 = Vars.m * 0.5 * pow(Vars.vehicleRadius, 2);
|
||||||
|
|
||||||
|
double n = sqrt(398600 / pow(6678, 3));
|
||||||
|
double k1 = (Vars.I22 - Vars.I33) / Vars.I11;
|
||||||
|
double k2 = (Vars.I11 - Vars.I33) / Vars.I22;
|
||||||
|
double k3 = (Vars.I22 - Vars.I11) / Vars.I33;
|
||||||
|
|
||||||
|
double R11 = pow(10, 2);
|
||||||
|
double R22 = pow(10, 2);
|
||||||
|
double R33 = pow(10, 2);
|
||||||
|
|
||||||
|
double F11 = -2 * pow(n, 2) * 4 * k1;
|
||||||
|
double F22 = -2 * pow(n, 2) * 3 * k2;
|
||||||
|
double F33 = -2 * pow(n, 2) * k3;
|
||||||
|
|
||||||
|
double G31 = n * (1 - k1);
|
||||||
|
double G13 = n * (k3 - 1);
|
||||||
|
|
||||||
|
double d = 0.5;
|
||||||
|
/*
|
||||||
|
The following calculations are based on output of LQR.m to avoid working
|
||||||
|
with matrices in C++ Please see .m file for details on calculation.
|
||||||
|
Algorithm taken from LQR wikipedia page:
|
||||||
|
https://en.wikipedia.org/wiki/Algebraic_Riccati_equation#Solution
|
||||||
|
*/
|
||||||
|
double gain = 0.25;
|
||||||
|
|
||||||
|
double K11 =
|
||||||
|
-1 * gain *
|
||||||
|
(Vars.I33 * pow(abs(F33), 2) * pow(abs(Vars.I33), 4) * pow(abs(R33), 2) +
|
||||||
|
R33 * pow(abs(G31), 2) * pow(abs(Vars.I33), 2) + Vars.I33) /
|
||||||
|
(R11 * d * Vars.I11 *
|
||||||
|
(pow(abs(F33), 2) * pow(abs(Vars.I33), 4) * pow(abs(R33), 2) + 1));
|
||||||
|
double K22 = -1 * gain * Vars.I33 / (R22 * d * Vars.I22);
|
||||||
|
double K33 =
|
||||||
|
-1 * gain *
|
||||||
|
(Vars.I33 *
|
||||||
|
(Vars.I33 * pow(abs(F11), 2) * pow(abs(Vars.I11), 4) * pow(abs(R11), 2) +
|
||||||
|
R11 * pow(abs(G13), 2) * pow(abs(Vars.I11), 2) + Vars.I33)) /
|
||||||
|
(R33 * d * pow(abs(Vars.I33), 2) *
|
||||||
|
(pow(abs(F11), 2) * pow(abs(Vars.I11), 4) * pow(abs(R11), 2) + 1));
|
||||||
|
double K34 =
|
||||||
|
gain * (R11 * pow(abs(Vars.I11), 2) * G13) /
|
||||||
|
(R33 * Vars.I33 *
|
||||||
|
(pow(abs(F11), 2) * pow(abs(Vars.I11), 4) * pow(abs(R11), 2) + 1));
|
||||||
|
double K16 =
|
||||||
|
gain * (R33 * pow(abs(Vars.I33), 2) * G31) /
|
||||||
|
(R11 * Vars.I11 *
|
||||||
|
(pow(abs(F33), 2) * pow(abs(Vars.I33), 4) * pow(abs(R33), 2) + 1));
|
||||||
|
|
||||||
|
// Matrix Multiply K with [YPR/2; w123] column vector and divide by moment arm
|
||||||
|
double momentArm = 0.145;
|
||||||
|
Vars.LQRx = (K11 * Vars.yaw / 2 + K16 * Vars.rolldot) / momentArm;
|
||||||
|
Vars.LQRy = (K22 * Vars.pitch / 2) / momentArm;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TVC(struct sVars &Vars, double g)
|
||||||
|
{
|
||||||
|
if (Vars.thrust < 1)
|
||||||
|
{
|
||||||
|
// Define forces and moments for t = 0
|
||||||
|
Vars.Fx = 0;
|
||||||
|
Vars.Fy = 0;
|
||||||
|
Vars.Fz = g * Vars.m0;
|
||||||
|
|
||||||
|
Vars.momentX = 0;
|
||||||
|
Vars.momentY = 0;
|
||||||
|
Vars.momentZ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Convert servo position to degrees for comparison to max allowable
|
||||||
|
Vars.xServoDegs = (180 / 3.1416) * 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 / 3.1416) * 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 * (3.1416 / 180));
|
||||||
|
Vars.Fy = Vars.thrust * sin(Vars.yServoDegs * (3.1416 / 180));
|
||||||
|
Vars.Fz = sqrt(pow(Vars.thrust, 2) - (pow(Vars.Fx, 2) + pow(Vars.Fy, 2))) +
|
||||||
|
(Vars.m * g);
|
||||||
|
|
||||||
|
// Calculate moment created by Fx and Fy
|
||||||
|
double momentArm = 0.145;
|
||||||
|
Vars.momentX = Vars.Fx * momentArm;
|
||||||
|
Vars.momentY = Vars.Fy * momentArm;
|
||||||
|
Vars.momentZ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void vehicleDynamics(struct sVars &Vars, int t)
|
||||||
|
{
|
||||||
|
// Idot
|
||||||
|
if (t < 1)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
Vars.x = 0;
|
||||||
|
Vars.y = 0;
|
||||||
|
|
||||||
|
Vars.ax = 0;
|
||||||
|
Vars.ay = 0;
|
||||||
|
Vars.az = Vars.Fz / Vars.m0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.m) + (Vars.pitchdot * Vars.vz - Vars.rolldot * Vars.vy);
|
||||||
|
Vars.ay =
|
||||||
|
(Vars.Fy / Vars.m) + (Vars.rolldot * Vars.vx - Vars.vz * Vars.yawdot);
|
||||||
|
Vars.az =
|
||||||
|
(Vars.Fz / Vars.m) + (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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 / 3.1416 << ", ";
|
||||||
|
outfile << Vars.pitch * 180 / 3.1416 << ", ";
|
||||||
|
outfile << Vars.roll * 180 / 3.1416 << ", ";
|
||||||
|
|
||||||
|
outfile << Vars.yawdot * 180 / 3.1416 << ", ";
|
||||||
|
outfile << Vars.pitchdot * 180 / 3.1416 << ", ";
|
||||||
|
outfile << Vars.rolldot * 180 / 3.1416 << ", ";
|
||||||
|
|
||||||
|
outfile << Vars.xServoDegs << ", ";
|
||||||
|
outfile << Vars.yServoDegs << ", ";
|
||||||
|
|
||||||
|
outfile << Vars.m << ", ";
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
double dxdt = (x2 - x1) / (dt / 1000);
|
||||||
|
return dxdt;
|
||||||
|
}
|
||||||
|
|
||||||
|
double integral(double x, double y, double dt)
|
||||||
|
{
|
||||||
|
double integ = (x * dt / 1000) + y;
|
||||||
|
return integ;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user