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

Attitude model v2 #198

Merged
merged 85 commits into from
Jan 30, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
0610412
visualization code from examples, added thermal sim to get familiar (…
Mr-Medina Dec 25, 2023
fa7c867
added Earth-Centered Inertial Frame (ECI) to Roll-Pitch-Yaw (RPY) ref…
Mr-Medina Dec 26, 2023
01e9f74
added function to transform a vector from ECI to RPY. (also added a f…
Mr-Medina Dec 26, 2023
0242126
added transformation matrix for RPY to body fixed frames
Mr-Medina Dec 26, 2023
86c55ca
RPY to body fixed vector transformation functions added
Mr-Medina Dec 26, 2023
e967cc4
v1 reference frame transfer file. cleaned up comments. inputs: lists …
Mr-Medina Dec 26, 2023
53a8a34
Some cleaning up
Mr-Medina Dec 26, 2023
3993c6a
added functions for user to identify disturbances (aero, gravitationa…
Mr-Medina Dec 28, 2023
07047e4
created disturbance function file
Mr-Medina Dec 28, 2023
935ccc4
disturbance torque in attitude model
Mr-Medina Dec 28, 2023
dfa12e5
added case for zero euler angles (for ref frame transfers)
Mr-Medina Dec 28, 2023
7cd2e31
initial onditions added
Mr-Medina Dec 28, 2023
e2b5351
Now able to call attitude in rad and deg from spacecraft actor.
Mr-Medina Dec 28, 2023
ce85d15
added some dynamics to attitude model (not complete at all, needs to …
Mr-Medina Dec 28, 2023
eb4ba79
added more dynamics but I think its wrong (too simple)
Mr-Medina Dec 28, 2023
da4ba34
added has_attitude_model function
Mr-Medina Dec 28, 2023
3b214e4
fixed error converting angles
Mr-Medina Dec 28, 2023
70c9a61
added get_previous_position function
Mr-Medina Dec 28, 2023
8ebaeea
update atitude model in paseos
Mr-Medina Dec 28, 2023
0a0cdad
fixing ref frame transformations
Mr-Medina Dec 28, 2023
3cea066
TODO add pointing vector in inertial frame, updating extra component …
Mr-Medina Dec 28, 2023
608ef32
test file to see if model makes some sensez
Mr-Medina Dec 28, 2023
dd38d0c
added function (might be deleted later) and fixed some stuff
Mr-Medina Dec 29, 2023
62e97f5
play python file to plot attitude. Works with plotting Nadir vector
Mr-Medina Dec 29, 2023
b4080b3
commit attitude model before changing most of it (to get dynamics cor…
Mr-Medina Dec 29, 2023
8a67834
play file fixed
Mr-Medina Dec 29, 2023
385ccb0
tried to apply correct dynamics. Not there yet
Mr-Medina Dec 30, 2023
e28964e
get_euler, angles can now also be negative. Right handed system applied
Mr-Medina Dec 30, 2023
438eca6
Update base_actor.py
Mr-Medina Dec 30, 2023
4c0457b
Update spacecraft_actor.py
Mr-Medina Dec 30, 2023
7f7f893
Update play.py
Mr-Medina Dec 30, 2023
1494585
Update attitude_model.py
Mr-Medina Dec 30, 2023
a18cd6a
changed translation= to default False, Euler angle function is redund…
Mr-Medina Jan 2, 2024
195c28e
model "v3" works with constant angular velocity, breaks after certain…
Mr-Medina Jan 2, 2024
967b177
set_attitude_model: added correct arguments
Mr-Medina Jan 2, 2024
376a565
own test file
Mr-Medina Jan 2, 2024
0c90588
Attitude model now correctly models attitude with constant angular ve…
Mr-Medina Jan 2, 2024
78594d0
Needs to be fixed: with z angular velocity, roll is introduced
Mr-Medina Jan 2, 2024
fc3a857
different transformation matrix (roll pitch yaw angles are not the sa…
Mr-Medina Jan 3, 2024
0a537a7
one rotation (depending on the transformation sequence in body_to_rpy…
Mr-Medina Jan 3, 2024
3d4b351
Model works with constant angular velocity input, outputs correct poi…
Mr-Medina Jan 3, 2024
7f6f144
minor adjustments normalizing input pointing vector, todo added
Mr-Medina Jan 3, 2024
6f7c781
minor adjustments normalizing input pointing vector, sign fixed
Mr-Medina Jan 3, 2024
816f155
use rodriguez rotations instead of reference frame rotations (this do…
Mr-Medina Jan 4, 2024
4b1e5d3
added rodriguez rotation function
Mr-Medina Jan 4, 2024
aba8df1
implemented rodriguez rotation for both rotations of the body frame
Mr-Medina Jan 4, 2024
0b444dd
body to rpy convention: yaw - pitch - roll. transformation functions …
Mr-Medina Jan 4, 2024
4a5ebee
added function to get rpy angles, todo: perform actual body rotations…
Mr-Medina Jan 5, 2024
270d859
Now model works with initial attitude specified, calculates attitude …
Mr-Medina Jan 8, 2024
67864ff
Clean up code + added acceleration calculations (deleted possibility …
Mr-Medina Jan 9, 2024
4a130b3
fixed problem where when pitch = 90 deg, it stays 90.
Mr-Medina Jan 9, 2024
d8b6abe
code cleanup, more comments, rodrigues instead of rodriguez, moved re…
Mr-Medina Jan 9, 2024
a68f04d
renamed play file to test attitude plotting
Mr-Medina Jan 9, 2024
9e4b78d
attitude model pull request
Mr-Medina Jan 10, 2024
724e9f5
Removed own test files for pr
Mr-Medina Jan 10, 2024
6ce55d7
Added plotting file back to branch for visually checking attitude model
Mr-Medina Jan 10, 2024
3633631
implemented some feedback
Mr-Medina Jan 11, 2024
5fe2dc3
Merge branch 'attitude-model' into Attitude_pointing
Moanalengkeek Jan 19, 2024
ff93e5f
Merge pull request #194 from Mr-Medina/Attitude_pointing
Moanalengkeek Jan 19, 2024
db97bd7
Implemented geometric model, angular velocity vector is also possible…
Mr-Medina Jan 19, 2024
0f68861
visual test for attitude plotting cleaned up a bit
Mr-Medina Jan 19, 2024
64b1ece
pull request #198 feedback
Mr-Medina Jan 23, 2024
28c55de
pull request #198 feedback
Mr-Medina Jan 23, 2024
b645b3b
pull request #198 feedback
Mr-Medina Jan 23, 2024
612b3b2
pull request #198 feedback
Mr-Medina Jan 23, 2024
d818d3f
Apply suggestions from code review
Mr-Medina Jan 23, 2024
71c3f50
Apply suggestions from code review
Mr-Medina Jan 23, 2024
7dd542b
Apply suggestions from code review
Mr-Medina Jan 23, 2024
aa21573
Apply suggestion from code review
Mr-Medina Jan 23, 2024
55b6443
Apply suggestion from code review
Mr-Medina Jan 23, 2024
50ceeac
Fixed time discrepancies of model. both rotations now applied at corr…
Mr-Medina Jan 24, 2024
428a75e
formatting
Mr-Medina Jan 24, 2024
9732308
Attitude model also runs without set_disturbances (for test file)
Mr-Medina Jan 25, 2024
7b6db6d
Added two tests, one for attitude model with known angular velocity, …
Moanalengkeek Jan 25, 2024
11eb784
setting disturbances when no disturbances used.
Mr-Medina Jan 25, 2024
8b1d525
Added additional test to confirm conditions after 1 orbit are initial…
Moanalengkeek Jan 26, 2024
0a66921
Merge remote-tracking branch 'origin/attitude-model' into attitude-model
Mr-Medina Jan 26, 2024
f0522e4
added attitude tests
Mr-Medina Jan 26, 2024
ddf1006
Detele file for pr
Mr-Medina Jan 27, 2024
536f606
Commenting
Mr-Medina Jan 27, 2024
5a3dbc2
Merge remote-tracking branch 'origin/student' into attitude-model
Mr-Medina Jan 28, 2024
ac935cc
attitude model bug with geometric model interaction fixed
Mr-Medina Jan 28, 2024
747a270
Apply suggestion from code review
Mr-Medina Jan 29, 2024
4240289
made functions in attitude model internal
Mr-Medina Jan 29, 2024
dee082b
made functions in attitude model internal
Mr-Medina Jan 29, 2024
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
4 changes: 2 additions & 2 deletions paseos/actors/actor_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@ def set_disturbances(
Args:
actor (SpacecraftActor): The actor to add to.
aerodynamic (bool): Whether to consider aerodynamic disturbances in the attitude model. Defaults to False
gravitational (bool): Whether to consider gravitational disturbances in the attitude model. Defaults to False
gravitational (bool): Whether to consider gravity disturbances in the attitude model. Defaults to False
magnetic (bool): Whether to consider magnetic disturbances in the attitude model. Defaults to False
"""
# Create a list with user specified disturbances which are considered in the attitude modelling.
Expand Down Expand Up @@ -562,7 +562,7 @@ def set_attitude_model(
Args:
actor (SpacecraftActor): Actor to model.
actor_initial_attitude_in_rad (list of floats): Actor's initial attitude. Defaults to [0.0, 0.0, 0.0].
actor_initial_angular_velocity (list of floats): Actor's initial angular velocity Defaults to [0.0, 0.0, 0.0].
actor_initial_angular_velocity (list of floats): Actor's initial angular velocity. Defaults to [0.0, 0.0, 0.0].
actor_pointing_vector_body (list of floats): Actor's pointing vector. Defaults to [0.0, 0.0, 1.0].
"""

Expand Down
9 changes: 9 additions & 0 deletions paseos/actors/base_actor.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,15 @@ def has_attitude_model(self) -> bool:
"""
return hasattr(self, "_attitude_model") and self._attitude_model is not None

@property
def has_attitude_disturbances(self) -> bool:
"""Returns true if actor has attitude disturbances attributed, else false.

Returns:
bool: bool indicating presence.
"""
return hasattr(self, "_disturbances") and self._disturbances is not None

@property
def mass(self) -> float:
"""Returns actor's mass in kg.
Expand Down
49 changes: 30 additions & 19 deletions paseos/attitude/attitude_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,40 +36,50 @@ class AttitudeModel:
_actor_pointing_vector_body = None
_actor_pointing_vector_eci = None

# _actor_prev_pos = None
def __init__(
self,
local_actor,
# initial conditions: (defaults to 0)
actor_initial_attitude_in_rad: list[float] = [0.0, 0.0, 0.0],
actor_initial_angular_velocity: list[float] = [0.0, 0.0, 0.0],
# pointing vector in body frame: (defaults to z-axis)
actor_pointing_vector_body: list[float] = [0.0, 0.0, 1.0]
## add args with default value = ...
# actor_dipole
# actor_drag_coefficient (more for geometric model)
# body_J2
# initial conditions:
actor_initial_attitude_in_rad: list[float] = [0., 0., 0.],
actor_initial_angular_velocity: list[float] = [0., 0., 0.],
# pointing vector in body frame: (defaults to body z-axis)
actor_pointing_vector_body: list[float] = [0., 0., 1.]
):
""" Creates an attitude model to model actor attitude based on
initial conditions (initial attitude and angular velocity) and
external disturbance torques.

Args:
actor (SpacecraftActor): Actor to model.
actor_initial_attitude_in_rad (list of floats): Actor's initial attitude ([roll, pitch, yaw]) angles.
Defaults to [0., 0., 0.].
actor_initial_angular_velocity (list of floats): Actor's initial angular velocity vector.
Defaults to [0., 0., 0.].
actor_pointing_vector_body (list of floats): User defined vector in the Actor body. Defaults to [0., 0., 1]
"""
self._actor = local_actor
# convert to np.ndarray
self._actor_attitude_in_rad = np.array(actor_initial_attitude_in_rad)
self._actor_angular_velocity = np.array(actor_initial_angular_velocity)

# normalize inputted pointing vector & convert to np.ndarray
self._actor_pointing_vector_body = np.array(
actor_pointing_vector_body
) / np.linalg.norm(np.array(actor_pointing_vector_body))

# pointing vector expressed in Earth-centered inertial frame
self._actor_pointing_vector_eci = rpy_to_eci(
body_to_rpy(self._actor_pointing_vector_body, self._actor_attitude_in_rad),
np.array(self._actor.get_position(self._actor.local_time)),
np.array(self._actor.get_position_velocity(self._actor.local_time)[1]),
)

# angular velocity vector expressed in Earth-centered inertial frame
self._actor_angular_velocity_eci = rpy_to_eci(
body_to_rpy(self._actor_angular_velocity, self._actor_attitude_in_rad),
np.array(self._actor.get_position(self._actor.local_time)),
np.array(self._actor.get_position_velocity(self._actor.local_time)[1]),
)
self._first_run = True

def nadir_vector(self):
# unused but might be useful during disturbance calculations or pointing vector relative position
Expand All @@ -87,22 +97,23 @@ def calculate_disturbance_torque(self):
Returns:
np.array([Tx, Ty, Tz]): total combined torques in Nm expressed in the spacecraft body frame.
"""

T = np.array([0.0, 0.0, 0.0])
if "aerodynamic" in self._actor.get_disturbances():
T += calculate_aero_torque()
if "gravitational" in self._actor.get_disturbances():
T += calculate_grav_torque()
if "magnetic" in self._actor.get_disturbances():
T += calculate_magnetic_torque()

if self._actor.has_attitude_disturbances:
if "aerodynamic" in self._actor.get_disturbances():
T += calculate_aero_torque()
if "gravitational" in self._actor.get_disturbances():
T += calculate_grav_torque()
if "magnetic" in self._actor.get_disturbances():
T += calculate_magnetic_torque()
return T

def calculate_angular_acceleration(self):
"""Calculate the spacecraft angular acceleration (external disturbance torques and gyroscopic accelerations)."""
# TODO in the future control torques could be added

# moment of Inertia matrix:
I = self._actor._moment_of_inertia
I = self._actor._moment_of_inertia()

# Euler's equation for rigid body rotation: a = I^(-1) (T - w x (Iw))
# with: a = angular acceleration, I = inertia matrix, T = torque vector, w = angular velocity
Expand Down
170 changes: 170 additions & 0 deletions paseos/tests/attitude_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
"""Tests to see whether the attitude and disturbance models work as intended"""

import numpy as np
import pykep as pk
import sys

sys.path.append("../..")
import paseos
from paseos import ActorBuilder, SpacecraftActor


def attitude_model_test():
"""Testing the attitude model with no disturbances and known angular velocity.
One actor has orbit in Earth inertial x-y plane (equatorial) with initial velocity which rotates the actor with 180°
in 20 steps advancing time 100 seconds (pi/ (20 * 100)).
Another one has zero initial angular velocity.
This test mainly checks whether the model correctly models constant angular velocity without disturbances
"""

earth = pk.planet.jpl_lp("earth")

# First actor constant angular acceleration
omega = np.pi/2000

# Define first local actor with angular velocity
sat1 = ActorBuilder.get_actor_scaffold("sat1", SpacecraftActor, pk.epoch(0))
ActorBuilder.set_orbit(sat1, [7000000, 0, 0], [0, 8000.0, 0], pk.epoch(0), earth)
ActorBuilder.set_geometric_model(sat1, mass=100)
ActorBuilder.set_attitude_model(
sat1,
actor_initial_angular_velocity=[0.0, omega, 0.0],
actor_pointing_vector_body=[0, 0, 1],
)

# Define second local actor without angular velocity
sat2 = ActorBuilder.get_actor_scaffold("sat2", SpacecraftActor, pk.epoch(0))
ActorBuilder.set_orbit(sat2, [7000000, 0, 0], [0, 8000.0, 0], pk.epoch(0), earth)
ActorBuilder.set_geometric_model(sat2, mass=100)
ActorBuilder.set_attitude_model(
sat2,
actor_initial_angular_velocity=[0.0, 0.0, 0.0],
actor_pointing_vector_body=[0, 0, 1],
)

# Check Initial values

# sat1
assert np.all(sat1._attitude_model._actor_pointing_vector_body == [0.0, 0.0, 1.0])
assert np.all(sat1._attitude_model._actor_pointing_vector_eci == [-1.0, 0.0, 0.0])
assert np.all(sat1._attitude_model._actor_attitude_in_rad == [0.0, 0.0, 0.0])
# positive angular velocity in body y direction is negative angular velocity in Earth inertial z direction:
assert np.all(sat1._attitude_model._actor_angular_velocity_eci == [0.0, 0.0, -omega])

# sat2
assert np.all(sat2._attitude_model._actor_pointing_vector_body == [0.0, 0.0, 1.0])
assert np.all(sat2._attitude_model._actor_pointing_vector_eci == [-1.0, 0.0, 0.0])
assert np.all(sat2._attitude_model._actor_attitude_in_rad == [0.0, 0.0, 0.0])

# Initialise simulation
sim = paseos.init_sim(sat1)
sim.add_known_actor(sat2)
# Run simulation 20 steps
for i in range(20):
sim.advance_time(100, 0)

# Testing the simulation went as intended
# Pointing vector from sat1 must be rotated from [-1, 0, 0] to [1, 0, 0]:
assert np.all(np.isclose(sat1.pointing_vector(), np.array([1.0, 0.0, 0.0])))
# Sat1 angular velocity in the body frame must stay constant:
assert np.all(
np.isclose(
sat1._attitude_model._actor_angular_velocity,
np.array([0.0, omega, 0.0]),
)
)
# Sat1 angular velocity in the Earth inertial frame must stay constant:
assert np.all(
np.isclose(
sat1.angular_velocity(),
np.array([0.0, 0.0, -omega]),
)
)

# Pointing vector from sat2 must not be rotated.
assert np.all(sat2.pointing_vector() == np.array([-1.0, 0.0, 0.0]))
# Sat2 angular velocity in the body frame must stay zero:
assert np.all(sat2._attitude_model._actor_angular_velocity == np.array([0.0, 0.0, 0.0]))


def attitude_thermal_model_test():
"""Testing the attitude model with no disturbances and no angular velocity, and ensuring the attitude model doesn't
break the thermal model (or vice versa)"""
earth = pk.planet.jpl_lp("earth")

# Define local actor
sat1 = ActorBuilder.get_actor_scaffold("sat1", SpacecraftActor, pk.epoch(0))
ActorBuilder.set_orbit(sat1, [7000000, 0, 0], [0, 8000.0, 0], pk.epoch(0), earth)
ActorBuilder.set_geometric_model(sat1, mass=100)
ActorBuilder.set_thermal_model(
actor=sat1,
actor_mass=sat1.mass,
actor_initial_temperature_in_K=273.15,
actor_sun_absorptance=1.0,
actor_infrared_absorptance=1.0,
actor_sun_facing_area=1.0,
actor_central_body_facing_area=1.0,
actor_emissive_area=1.0,
actor_thermal_capacity=1000,
)
ActorBuilder.set_attitude_model(sat1, actor_pointing_vector_body=[0, 0, 1])

# Check Initial values
assert np.all(sat1._attitude_model._actor_pointing_vector_body == [0.0, 0.0, 1.0])
assert np.all(sat1._attitude_model._actor_attitude_in_rad == [0.0, 0.0, 0.0])
assert sat1.temperature_in_K == 273.15

# Initialise simulation
sim = paseos.init_sim(sat1)

# Run simulation 20 steps
for i in range(21):
vector = sat1.pointing_vector()
sim.advance_time(100, 0)

# Testing the simulation went as intended
assert vector[0] == -1.0
assert sat1._attitude_model._actor_angular_velocity[1] == 0.0
assert np.round(sat1._attitude_model._actor_attitude_in_rad[0], 3) == 3.142
assert np.round(sat1.temperature_in_K, 3) == 278.522


def attitude_and_orbit_test():
"""This test checks both the orbit calculations, as well as the attitude.
The input is a simple orbit, and the angular velocity if 2pi/period. This means the initial conditions should be
the same as the conditions after one orbit"""

earth = pk.planet.jpl_lp("earth")

# Define local actor
sat1 = ActorBuilder.get_actor_scaffold("sat1", SpacecraftActor, pk.epoch(0))
ActorBuilder.set_orbit(sat1, [7000000, 0, 0], [0, 5460.0, 0], pk.epoch(0), earth)
ActorBuilder.set_geometric_model(sat1, mass=100)
orbit_period = 2 * np.pi * np.sqrt((6371000 + 7000000) ** 3 / 3.986004418e14)
ActorBuilder.set_attitude_model(
sat1,
actor_initial_angular_velocity=[0.0, 2 * np.pi / orbit_period, 0.0],
actor_pointing_vector_body=[0, 0, 1],
)
ActorBuilder.set_disturbances(sat1)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Did you check with the others what is supposed to happen when all disturbances are set?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We will add seperate disturbance tests in this file for every disturbance. This line could be deleted.


# Check Initial values
assert np.all(sat1._attitude_model._actor_pointing_vector_body == [0.0, 0.0, 1.0])
assert np.all(sat1._attitude_model._actor_attitude_in_rad == [0.0, 0.0, 0.0])
vector = sat1.pointing_vector()
assert vector[0] == -1.0

# Initialise simulation
sim = paseos.init_sim(sat1)

# Run simulation 10 steps
for i in range(11):
vector = sat1.pointing_vector()
sim.advance_time(orbit_period / 10, 0)

# Testing the simulation went as intended
assert sat1._attitude_model._actor_pointing_vector_body[2] == 1.0
assert vector[0] == -1.0


attitude_model_test()
Mr-Medina marked this conversation as resolved.
Show resolved Hide resolved
Loading
Loading