Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Av 1076 fix monte python #41

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,5 @@ sensors:
bno:
error: !eval 2.5/3
meta:
output_file: '../output/simulated_6dof.csv'
monte_carlo_output_folder: '../output/monte_carlo'
output_file: '../../output/simulated_6dof.csv'
monte_carlo_output_folder: '../../output/monte_carlo'
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ rocket:
<<: *simulated_stage
rocket_body:
<<: *simulated_rocket_body
rasaero_lookup_file: "../lookup/RASAero.csv"
rasaero_lookup_file: "../../Configurations/LookUp/RASAero.csv"
C_d: 0.5
C_d_s: 1.2
length: 6.68
Expand Down Expand Up @@ -34,7 +34,7 @@ rocket:
<<: *simulated_stage
rocket_body:
<<: *simulated_rocket_body
rasaero_lookup_file: "../lookup/RASAero.csv"
rasaero_lookup_file: "../../Configurations/LookUp/RASAero.csv"
C_d: 0.5
C_d_s: 1.2
length: 3.34
Expand All @@ -60,7 +60,7 @@ rocket:
max_ext_spd: 0.001
desired_apogee: 4572
meta:
output_file: '../output/simulated_6dof.csv'
monte_carlo_output_folder: '../output/monte_carlo'
output_file: '../../Output/simulated_6dof.csv'
monte_carlo_output_folder: '../../Output/monte_carlo'


Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import yaml
import numpy
import os
from properties.yaml_datatypes import get_loader
import properties.properties as prop
import sys

from yaml_datatypes import get_loader
import properties as prop

config = None

Expand Down Expand Up @@ -46,12 +48,12 @@ def load_config(config_path):
raw_yaml = ""

# Load all data types and YAML structures
with open(os.path.join(os.path.dirname(__file__), "../properties/typedef.yaml")) as typedef:
with open(os.path.join(os.path.dirname(__file__), "typedef.yaml")) as typedef:
# Add yaml type definitions to current loaded file
raw_yaml += typedef.read()

# Load all ./templates
template_directory = os.path.join(os.path.dirname(__file__), "../properties/templates")
template_directory = os.path.join(os.path.dirname(__file__), "templates")
for template_filename in os.listdir(template_directory):
template = os.path.join(template_directory, template_filename)
# Check if template is a yaml file or not (All ./templates must be .yaml files.)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import numpy as np

# Config file
sim_config = "../properties/configs/staging_rocket.yaml"
sim_config = "configs/staging_rocket.yaml"

### Calculated constants
# Gravitational const
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,29 @@ define: &motor_M2500
impulse: 9671.0
motor_mass: 8.064
delay: 60
motor_lookup_file: "../lookup/m2500.csv"
motor_lookup_file: "../../Configurations/LookUp/m2500.csv"
cm: !numpy/array [0.3755, 0., 0.]

define: &motor_N5800
<<: *simulated_motor
impulse: 20145.7
motor_mass: 14.826
delay: 60
motor_lookup_file: "../lookup/n5800.csv"
motor_lookup_file: "../../Configurations/LookUp/n5800.csv"
cm: !numpy/array [0.3755, 0., 0.]

define: &motor_N2450
<<: *simulated_motor
impulse: 17907.0
motor_mass: 10.7
delay: 60
motor_lookup_file: "../lookup/n2540.csv"
motor_lookup_file: "../../Configurations/LookUp/n2540.csv"
cm: !numpy/array [0.3755, 0., 0.]

define: &motor_J244
<<: *simulated_motor
impulse: 849
motor_mass: 0.911
delay: 60
motor_lookup_file: "../lookup/j244.csv"
motor_lookup_file: "../../Configurations/LookUp/j244.csv"
cm: !numpy/array [0.3755, 0., 0.]
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@
- aerodynamic
- wind (comes from atmosphere class)
'''
import dynamics.motor as motor
import environment.atmosphere as atmosphere
import properties.properties as prop
import numpy as np
import util.vectors as vct
import pandas as pd
import os
import random
import sys

sys.path.insert(0, os.path.abspath(
os.path.join(os.path.dirname(__file__), '..','..','Configurations')))
import properties as prop

# Define Objects

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import numpy as np
import scipy
import random
import matplotlib.pyplot as plt
# import dynamics.forces as forces
import util.vectors as vct
# import properties.properties as prop

import dynamics.rocket as rocket_model
import environment.atmosphere as atm_model

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ def add_to_dict(self, x, baro_alt, accel, bno_ang_pos, gyro, kalman_filter, kf_c
self.sim_dict["motor_mass"].append(motor_mass)

# Converts the data saved in this sim into csv
def to_csv(self):
def to_list(self):
#Output
record = []
for point in range(len(self.sim_dict["time"])):
Expand Down Expand Up @@ -303,8 +303,8 @@ def to_csv(self):

record.append(cur_point)
return record


# if __name__ == '__main__':
# rocket = Rocket(motor_mass=5,rocket_dry_mass=2)
# print(rocket.rocket_total_mass)
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import numpy as np
import util.vectors as vct
import random
import properties.properties as prop
import properties.data_loader as dataloader
import os
import sys

import environment.atmosphere as atm

sys.path.insert(0, os.path.abspath(
os.path.join(os.path.dirname(__file__), '..','..','Configurations')))
import properties as prop
import data_loader as dataloader

def get_accelerometer_data(x_state, sensor_config):
"""Returns the accelerometer data in the body frame of the rocket.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ def get_wind_vector(self, tStamp)->np.ndarray:
current_wind_direction_ = np.zeros(3)
if self.enable_direction_variance_:
if((tStamp - self.last_direction_variance_update_) >= self.direction_variance_update_rate_):
generated_direction_variance = np.random.normal(self.nominal_wind_direction_, 3)
generated_direction_variance = np.random.normal(self.nominal_wind_direction_, self.wind_direction_variance_stddev_)
generated_direction_variance = generated_direction_variance / np.linalg.norm(generated_direction_variance)
self.last_direction_variance_update_ = tStamp

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import numpy as np
import scipy
import matplotlib.pyplot as plt
import os
import sys
import pandas as pd
import math

import dynamics.forces as forces
import util.vectors as vct
import properties.properties as prop
import dynamics.rocket as rocket_model

sys.path.insert(0, os.path.abspath(
os.path.join(os.path.dirname(__file__), '..','..','Configurations')))

import properties as prop
class Apogee:
'''Apogee Estimator Class

Expand Down
Original file line number Diff line number Diff line change
@@ -1,66 +1,28 @@
# ______ _____ _ __________ ___________
# | ___ \ / ___(_) / ___| _ \ _ | ___|
# | |_/ / _\ `--. _ _ __ ___ / /___| | | | | | | |_
# | __/ | | |`--. \ | '_ ` _ \ | ___ \ | | | | | | _|
# | | | |_| /\__/ / | | | | | | | \_/ | |/ /\ \_/ / |
# \_| \__, \____/|_|_| |_| |_| \_____/___/ \___/\_|
# __/ |
# |___/

# A 6DOF RK-4 Based simulation that uses RASAero aerodynamic data and known motor thrust data to simulate motion of the rocket
# with simulated sensor data as well as a implementation of the Extended Kalman Filter and active drag PID controller for the ISS
# Spaceshot entry for the 2023 IREC competition. This simulation was used to quantify the effects of the airbrakes, test
# different system design methodlogies, and provide preliminary tuning for the EKF and controller prior to implementation in
# SILSIM and flight software.
#
# 2022-2023 Guidance, Navigation, and Control Main Contributors #
# Sub-Team Lead: Parth Shrotri (2024)
# Colin Kinsey (2024)
# Evan Yu (2025)
# Rithvik Bhogavilli (2025)
# Kabir Cheema (2025)
# Freya Bansal (2025)
# Ishaan Bansal (2025)
# Ethan Pereira (2026)

import numpy as np
import matplotlib.pyplot as plt
import os
import sys
import shutil

sys.path.insert(0, os.path.abspath(
os.path.join(os.path.dirname(__file__), '..')))

import estimation.ekf as ekf
import estimation.r_ekf as r_ekf
import properties.properties as prop
import properties.data_loader as dataloader
import simulator as sim_class
import dynamics.sensors as sensors
import time
import estimation.apogee_estimator as apg
import dynamics.rocket as rocket_model
import environment.atmosphere as atmosphere

# Load desired config file
config = dataloader.config

# Runs simulation for the specific component of the rocket
class Simulation:
# dt can be dynamic in the future, so we need to
def __init__(self, rocket, motor, dt, x0, time_stamp=0, stages=[]):
def __init__(self, sim, rocket, atm, dt, x0, kf_dt, time_stamp=0, stages=[]):
self.sim = sim
self.rocket = rocket
self.stages = stages
self.motor = motor
self.motor = rocket.motor
self.atm = atm
self.dt = dt
self.x = x0.copy()
self.baro = 0
self.time_stamp = time_stamp
self.sensor_config = self.rocket.stage_config['sensors']
self.init_kalman_filters()
self.init_gnc(kf_dt)

def init_kalman_filters(self):
def init_gnc(self, dt):
# TODO: Init with previous rocket data
self.kalman_filter = ekf.KalmanFilter(dt, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
# TODO: init this data with the previous rocket becuase of staging
Expand All @@ -82,7 +44,7 @@ def init_kalman_filters(self):
pitch = -1 * (np.arctan2(-az,-ay) + np.pi/2)
yaw = np.arctan2(-ax,-ay) + np.pi/2
self.r_kalman_filter = r_ekf.KalmanFilter_R(dt, 0.0, 0.0, 0.0, pitch, 0.0, 0.0, yaw, 0.0, 0.0)
self.apogee_estimator = apg.Apogee(self.kalman_filter.get_state(), 0.1, 0.01, 3, 30, atm, self.rocket.stage_config)
self.apogee_estimator = apg.Apogee(self.kalman_filter.get_state(), 0.1, 0.01, 3, 30, self.atm, self.rocket.stage_config)

def update_kalman(self, baro_alt, accel, gyro, bno_ang_pos):
self.kalman_filter.priori()
Expand All @@ -102,17 +64,18 @@ def idle_stage(self):
self.kalman_filter.reset_lateral_pos()
current_state, current_covariance, current_state_r = self.get_kalman_state()

self.rocket.add_to_dict(self.x, baro_alt, accel, bno_ang_pos, gyro, current_state, current_covariance, current_state_r, 0, current_state[0], self.rocket.get_rocket_dry_mass(), self.rocket.get_total_motor_mass(self.time_stamp), 0, dt)
self.rocket.add_to_dict(self.x, baro_alt, accel, bno_ang_pos, gyro, current_state, current_covariance, current_state_r, 0, current_state[0], self.rocket.get_rocket_dry_mass(), self.rocket.get_total_motor_mass(self.time_stamp), 0, self.dt)
self.time_step()

def execute_stage(self):
def execute_stage(self, print=False):
# Run the stages
stage_separation_delay = 1
self.rocket.get_motor().ignite(self.time_stamp)

ignition_time = self.time_stamp
start = True
print(f"Staged at {self.time_stamp}")
if print:
print(f"Staged at {self.time_stamp}")
while self.time_stamp < ignition_time + self.rocket.get_motor().get_burn_time() + stage_separation_delay:
# Get sensor data
baro_alt, accel, gyro, bno_ang_pos = self.get_sensor_data()
Expand All @@ -124,9 +87,9 @@ def execute_stage(self):
self.rocket.set_motor_mass(self.time_stamp)

is_staging = start and self.rocket.current_stage != -1
self.x, alpha = sim.RK4(self.x, dt, self.time_stamp, is_staging, 0)
self.x, alpha = self.sim.RK4(self.x, self.dt, self.time_stamp, is_staging, 0)

self.rocket.add_to_dict(self.x, baro_alt, accel, bno_ang_pos, gyro, current_state, current_covariance, current_state_r, alpha, apogee_est, self.rocket.get_rocket_dry_mass(), self.rocket.get_total_motor_mass(self.time_stamp), 0, dt)
self.rocket.add_to_dict(self.x, baro_alt, accel, bno_ang_pos, gyro, current_state, current_covariance, current_state_r, alpha, apogee_est, self.rocket.get_rocket_dry_mass(), self.rocket.get_total_motor_mass(self.time_stamp), 0, self.dt)
self.time_step()
if start:
start = False
Expand Down Expand Up @@ -159,56 +122,22 @@ def coast(self):

apogee_est = self.apogee_estimator.predict_apogee(current_state[0:3])

self.x, alpha = sim.RK4(self.x, dt, self.time_stamp, 0)
self.x, alpha = self.sim.RK4(self.x, self.dt, self.time_stamp, 0)

self.rocket.add_to_dict(self.x, baro_alt, accel, bno_ang_pos, gyro, current_state, current_covariance, current_state_r, alpha, apogee_est, self.rocket.get_rocket_dry_mass(), self.rocket.get_total_motor_mass(self.time_stamp), 0, dt)
self.rocket.add_to_dict(self.x, baro_alt, accel, bno_ang_pos, gyro, current_state, current_covariance, current_state_r, alpha, apogee_est, self.rocket.get_rocket_dry_mass(), self.rocket.get_total_motor_mass(self.time_stamp), 0, self.dt)
self.time_step()

def simulator(x0, rocket, motor, dt) -> None:
'''Method which handles running the simulation and logging sim data to dict

Args:
x0 (np.array): state vector initialized to 0s [6x3]
x: y: z:
[[pos, pos, pos],
[vel, vel, vel],
[accel, accel, accel],
[ang_pos, ang_pos, ang_pos],
[ang_vel, ang_vel, ang_vel],
[ang_accel, ang_accel, ang_accel]]
dt (float): time step between each iteration in simulation
'''
simulator = Simulation(rocket, motor, dt, x0, stages=rocket.stages)
simulator.idle_stage()
t_start = time.time()
simulator.run_stages()
simulator.coast()
t_end = time.time() - t_start
print(f"Runtime: {t_end:.2f} seconds")


if __name__ == '__main__':
x0 = np.zeros((6, 3))
x0[3] = [0, 0.05, 0]
dt = 0.01

atm = atmosphere.Atmosphere(enable_direction_variance=True, enable_magnitude_variance=True)

def gen_sim_objs(config, atmo_args):
atm = atmosphere.Atmosphere(wind_direction_variance_stddev=atmo_args.get("wind_direction_stddev", 0),
wind_magnitude_variance_stddev=atmo_args.get("wind_magnitude_stddev", 0),
enable_direction_variance=atmo_args.get("enable_direction_variance", False),
enable_magnitude_variance=atmo_args.get("enable_magnitude_variance", False),
nominal_wind_magnitude=atmo_args.get("nominal_wind_magnitude", 0.0),
nominal_wind_direction=atmo_args.get("nominal_wind_direction", np.array([0, 0, 0])))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably better for the sake of standardization and legibility to have each of these fields explicitly defined in the dictionary before being passed in

stages = []
for stage in config['rocket']['stages'][1:]:
stages.append(rocket_model.Rocket(stage, atm=atm))
rocket = rocket_model.Rocket(config['rocket']['stages'][0], atm=atm, stages=stages)

motor = rocket.motor
sim = sim_class.Simulator(atm=atm, rocket=rocket)

simulator(x0, rocket, motor, dt)

print("Writing to file...")

record = rocket.to_csv()
output_file = os.path.join(os.path.dirname(__file__), config["meta"]["output_file"])
with open(output_file, 'w') as f:
f.write("time,pos_x,pos_y,pos_z,vel_x,vel_y,vel_z,accel_x,accel_y,accel_z,ang_pos_x,ang_pos_y,ang_pos_z,ang_vel_x,ang_vel_y,ang_vel_z,ang_accel_x,ang_accel_y,ang_accel_z,alpha,rocket_total_mass,motor_mass,flap_ext,baro_alt,imu_accel_x,imu_accel_y,imu_accel_z,imu_ang_pos_x,imu_ang_pos_y,imu_ang_pos_z,imu_gyro_x,imu_gyro_y,imu_gyro_z,apogee_estimate,kalman_pos_x,kalman_vel_x,kalman_accel_x,kalman_pos_y,kalman_vel_y,kalman_accel_y,kalman_pos_z,kalman_vel_z,kalman_accel_z,pos_cov_x,vel_cov_x,accel_cov_x,pos_cov_y,vel_cov_y,accel_cov_y,pos_cov_z,vel_cov_z,accel_cov_z,kalman_rpos_x,kalman_rvel_x,kalman_raccel_x,kalman_rpos_y,kalman_rvel_y,kalman_raccel_y,kalman_rpos_z,kalman_rvel_z,kalman_raccel_z\n")
for point in record:
f.write(f"{','.join(point)}\n")
return atm, rocket

Loading