-
Notifications
You must be signed in to change notification settings - Fork 14
Student #205
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
base: main
Are you sure you want to change the base?
Student #205
Changes from 149 commits
0610412
fa7c867
01e9f74
0242126
86c55ca
e967cc4
53a8a34
3993c6a
07047e4
935ccc4
dfa12e5
7cd2e31
e2b5351
ce85d15
eb4ba79
da4ba34
3b214e4
70c9a61
8ebaeea
0a0cdad
3cea066
608ef32
dd38d0c
62e97f5
b4080b3
8a67834
385ccb0
e28964e
438eca6
4c0457b
7f7f893
1494585
a18cd6a
195c28e
967b177
376a565
0c90588
78594d0
fc3a857
0a537a7
3d4b351
7f6f144
6f7c781
816f155
4b1e5d3
aba8df1
0b444dd
4a5ebee
270d859
67864ff
4a130b3
d8b6abe
a68f04d
9e4b78d
724e9f5
6ce55d7
3633631
5fe2dc3
ff93e5f
db97bd7
0f68861
0259866
c792502
e8ceb9e
ba0f57c
0d585f9
59c3599
a2ad9fb
64b1ece
28c55de
b645b3b
612b3b2
d818d3f
71c3f50
7dd542b
87e09b8
b6602e1
aa21573
55b6443
50ceeac
428a75e
acb6aee
9732308
7b6db6d
11eb784
2f9969f
8b1d525
ccd3712
aacaa42
93f6332
3ce7dae
b42eac9
0a66921
f0522e4
b56c076
ce74572
ddf1006
536f606
d31310f
bdcd11b
f64cc0e
dcdc6f1
30d108f
e95504b
5a3dbc2
ac935cc
437d908
437b8d9
ef25a18
7914692
21d9634
747a270
8e37a3b
4240289
dee082b
43b29d9
f257760
e94520a
e51829e
bb1056f
3822fb5
a2cb141
884c0a4
70a4e27
084ae6d
3f13190
a9dc4ab
695f40e
50f0456
f1c3037
ed4828f
4d7640b
5987af2
96e2564
0b2d549
df16bc4
e042180
e1fb6ac
3e117bd
333196d
07d215b
a8032b1
0dd8c56
ad72734
f0e1a15
ef1d0d7
a6ef070
ff192ef
bc5bfd1
2e77458
624966d
1d7df19
5d184cf
363c11f
e9d8fce
020e53b
54a8621
9245ccb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
|
GabrieleMeoni marked this conversation as resolved.
GabrieleMeoni marked this conversation as resolved.
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,7 +13,8 @@ | |
| from ..thermal.thermal_model import ThermalModel | ||
| from ..power.power_device_type import PowerDeviceType | ||
| from ..radiation.radiation_model import RadiationModel | ||
| from paseos.geometric_model.geometric_model import GeometricModel | ||
| from .spacecraft_body_model import SpacecraftBodyModel | ||
| from ..attitude.attitude_model import AttitudeModel | ||
|
|
||
|
|
||
| class ActorBuilder: | ||
|
|
@@ -307,32 +308,49 @@ def set_position(actor: BaseActor, position: list): | |
| logger.debug(f"Setting position {position} on actor {actor}") | ||
|
|
||
| @staticmethod | ||
| def set_geometric_model( | ||
| def set_spacecraft_body_model( | ||
| actor: SpacecraftActor, mass: float, vertices=None, faces=None, scale: float = 1 | ||
| ): | ||
| """Define geometry of the spacecraft actor. This is done in the spacecraft body reference frame, and can be | ||
| transformed to the inertial/PASEOS reference frame using the reference frane transformations in the attitude | ||
| transformed to the inertial/PASEOS reference frame using the reference frame transformations in the attitude | ||
| model. When used in the attitude model, the geometric model is in the body reference frame. | ||
|
|
||
| Args: | ||
| actor (SpacecraftActor): Actor to update. | ||
| mass (float): Mass of the spacecraft in kg. | ||
| vertices (list): List of all vertices of the mesh in terms of distance (in m) from origin of body frame. | ||
| Coordinates of the corners of the object. If not selected, it will default to a cube that can be scaled. | ||
| vertices (list): List of coordinates [x, y, z] of the vertices of the mesh w.r.t. the body frame [m]. | ||
| If not selected, it will default to a cube that can be scaled. | ||
| by the scale. Uses Trimesh to create the mesh from this and the list of faces. | ||
| faces (list): List of the indexes of the vertices of a face. This builds the faces of the satellite by | ||
| defining the three vertices to form a triangular face. For a cuboid each face is split into two | ||
| triangles. Uses Trimesh to create the mesh from this and the list of vertices. | ||
| scale (float): Parameter to scale the cuboid by, defaults to 1. | ||
| """ | ||
| # check for spacecraft actor | ||
| assert isinstance( | ||
| actor, SpacecraftActor | ||
| ), "Body model is only supported for SpacecraftActors." | ||
|
|
||
| assert mass > 0, "Mass is > 0" | ||
|
|
||
| # Check if the actor already has mass. | ||
| if actor.mass: | ||
| logger.warning("The actor already had a mass. Overriding old mass value.") | ||
|
|
||
| actor._mass = mass | ||
| geometric_model = GeometricModel( | ||
| local_actor=actor, actor_mass=mass, vertices=vertices, faces=faces, scale=scale | ||
|
|
||
| # Check if the actor already had a has_spacecraft_body_model. | ||
| if actor.has_spacecraft_body_model: | ||
| logger.warning( | ||
| "The actor already had a spacecraft body model. Overriding old body bodel." | ||
| ) | ||
|
|
||
| # Create a spacraft body model | ||
| actor._spacecraft_body_model = SpacecraftBodyModel( | ||
| actor_mass=mass, vertices=vertices, faces=faces, scale=scale | ||
| ) | ||
| actor._mesh = geometric_model.set_mesh() | ||
| actor._moment_of_inertia = geometric_model.find_moment_of_inertia | ||
|
|
||
| # Check if the actor has a moment of inertia | ||
|
GabrieleMeoni marked this conversation as resolved.
Outdated
|
||
|
|
||
| @staticmethod | ||
| def set_power_devices( | ||
|
|
@@ -519,6 +537,81 @@ def set_thermal_model( | |
| power_consumption_to_heat_ratio=power_consumption_to_heat_ratio, | ||
| ) | ||
|
|
||
| @staticmethod | ||
| def set_attitude_disturbances( | ||
| actor: SpacecraftActor, | ||
| aerodynamic: bool = False, | ||
| gravitational: bool = False, | ||
| magnetic: bool = False, | ||
| ): | ||
| """Enables the attitude disturbances to be considered in the attitude modelling for an actor. | ||
|
|
||
| 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 gravity disturbances in the attitude model. Defaults to False. | ||
| magnetic (bool): Whether to consider magnetic disturbances in the attitude model. Defaults to False. | ||
|
GabrieleMeoni marked this conversation as resolved.
|
||
| """ | ||
| # check for spacecraft actor | ||
| assert isinstance( | ||
| actor, SpacecraftActor | ||
| ), "Attitude disturbances are only supported for SpacecraftActors." | ||
|
|
||
| assert ( | ||
| actor.has_attitude_model | ||
| ), "The actor has no attitude model. Impossible to set attitude disturbances." | ||
|
|
||
| # Create a list with user specified disturbances which are considered in the attitude modelling. | ||
| disturbance_list = [] | ||
|
|
||
| if aerodynamic: | ||
| disturbance_list.append("aerodynamic") | ||
| if gravitational: | ||
| disturbance_list.append("gravitational") | ||
| if magnetic: | ||
| disturbance_list.append("magnetic") | ||
| # Set attitude models. | ||
| actor._attitude_model._disturbances = disturbance_list | ||
|
GabrieleMeoni marked this conversation as resolved.
Outdated
GabrieleMeoni marked this conversation as resolved.
Outdated
|
||
|
|
||
| @staticmethod | ||
| def set_attitude_model( | ||
| actor: SpacecraftActor, | ||
| 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], | ||
| actor_pointing_vector_body: list[float] = [0.0, 0.0, 1.0], | ||
| actor_residual_magnetic_field: list[float] = [0.0, 0.0, 0.0], | ||
| ): | ||
| """Add an attitude model to the actor based on initial conditions: attitude (roll, pitch & yaw angles) | ||
| and angular velocity vector, modeling the evolution of the user specified pointing vector. | ||
|
|
||
| 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_pointing_vector_body (list of floats): Actor's pointing vector. Defaults to [0.0, 0.0, 1.0]. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. isn't attitude and pointing vec the same?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The problem is that a pointing vector alone is not sufficient to define the attitude (i.e., if you have a satellite pointing to a specific direction, all the rotations around the axis passing through the pointing vector will have a different attitude but the same pointing vector). So, the pointing vector definition is arbitrary, while the attitude is not.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe it would be good add a link to explanation of attitude? ideally in the readme with the minimal example?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, it is in my TODO list. But I am waiting that we are both happy with the class architecture, methods, and so on, to avoid to have to redo it.
GabrieleMeoni marked this conversation as resolved.
Outdated
|
||
| actor_residual_magnetic_field (list of floats): Actor's residual magnetic dipole moment vector. | ||
|
GabrieleMeoni marked this conversation as resolved.
Outdated
GabrieleMeoni marked this conversation as resolved.
Outdated
GabrieleMeoni marked this conversation as resolved.
Outdated
|
||
| Defaults to [0.0, 0.0, 0.0]. | ||
| """ | ||
| # check for spacecraft actor | ||
|
GabrieleMeoni marked this conversation as resolved.
GabrieleMeoni marked this conversation as resolved.
|
||
| assert isinstance( | ||
| actor, SpacecraftActor | ||
| ), "Attitude model is only supported for SpacecraftActors" | ||
|
|
||
| # Check if actor has already an attitude model. | ||
| if actor.has_attitude_model: | ||
| logger.warning( | ||
| "The actor already had an attitude model. Overriding old attitude model." | ||
| ) | ||
|
|
||
| # Set attitude model. | ||
| actor._attitude_model = AttitudeModel( | ||
| local_actor=actor, | ||
| actor_initial_attitude_in_rad=actor_initial_attitude_in_rad, | ||
| actor_initial_angular_velocity=actor_initial_angular_velocity, | ||
| actor_pointing_vector_body=actor_pointing_vector_body, | ||
| actor_residual_magnetic_field=actor_residual_magnetic_field, | ||
| ) | ||
|
|
||
| @staticmethod | ||
| def add_comm_device(actor: BaseActor, device_name: str, bandwidth_in_kbps: float): | ||
| """Creates a communication device. | ||
|
|
@@ -539,7 +632,10 @@ def add_comm_device(actor: BaseActor, device_name: str, bandwidth_in_kbps: float | |
|
|
||
| @staticmethod | ||
| def add_custom_property( | ||
| actor: BaseActor, property_name: str, initial_value: Any, update_function: Callable | ||
| actor: BaseActor, | ||
| property_name: str, | ||
| initial_value: Any, | ||
| update_function: Callable, | ||
| ): | ||
| """Adds a custom property to the actor. This e.g. allows tracking any physical | ||
| the user would like to track. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| from loguru import logger | ||
| import numpy as np | ||
| import pykep as pk | ||
| from loguru import logger | ||
|
|
||
| from paseos.actors.base_actor import BaseActor | ||
| from paseos.power import discharge_model | ||
|
|
@@ -19,8 +20,10 @@ class SpacecraftActor(BaseActor): | |
| # Actor's mass in kg | ||
| _mass = None | ||
|
|
||
| _spacecraft_body_model = None | ||
| _thermal_model = None | ||
| _radiation_model = None | ||
| _attitude_model = None | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now, if I actually want to use this as a user I most likely don't want my spacecraft to just tumble out of control. I think we should add a function to set the actors attitude? (allowing users to simulate corrective maneuvers)
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point. There are two solutions:
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not just a function to setting the current pointing/attitude? Super simple to implement and allows you implement more complex interaction via custom parameters etc.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will add it. But, just to clarify: if you do not call
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (please don't resolve if I should read because it will be hidden :P) I would suggest to move the attitude into actor (maybe even base_actor?) since pointing / attitude of the actor can be interesting even if it is not disturbed or maybe even for ground station (think ground station antenna pointing)?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, I am resolving stuff because there are so many comments that I lose track of what I have to implement xD |
||
|
|
||
| # If radiation randomly restarted the device | ||
| _was_interrupted = False | ||
|
|
@@ -104,6 +107,46 @@ def mass(self) -> float: | |
| """ | ||
| return self._mass | ||
|
|
||
| @property | ||
| def body_mesh(self) -> np.array: | ||
| """Gives the mesh of the satellite. | ||
|
|
||
| Returns: | ||
| np.array: Mesh of the satellite. | ||
|
GabrieleMeoni marked this conversation as resolved.
|
||
| """ | ||
| return self._spacecraft_body_model._body_mesh | ||
|
|
||
| @property | ||
| def attitude_disturbances(self) -> list: | ||
| """Gives attitude disturbances list. | ||
|
|
||
| Returns: | ||
| list: attitude disturbances list. | ||
| """ | ||
| return self._attitude_model._disturbances | ||
|
|
||
| @property | ||
| def body_moment_of_inertia(self) -> np.array: | ||
| """Gives the moment of inertia of the actor, assuming constant density. | ||
|
|
||
| Returns: | ||
| np.array: Mass moments of inertia for the actor | ||
|
GabrieleMeoni marked this conversation as resolved.
Outdated
|
||
|
|
||
| I is the moment of inertia, in the form of [[Ixx Ixy Ixz] | ||
| [Iyx Iyy Iyx] | ||
| [Izx Izy Izz]] | ||
| """ | ||
| return self._spacecraft_body_model._body_moment_of_inertia | ||
|
|
||
| @property | ||
| def body_center_of_gravity(self) -> np.array: | ||
| """Gives the volumetric center of mass of the actor. | ||
|
|
||
| Returns: | ||
| np.array: Coordinates of the center of gravity of the mesh. | ||
| """ | ||
| return self._spacecraft_body_model._body_center_of_gravity | ||
|
GabrieleMeoni marked this conversation as resolved.
Outdated
|
||
|
|
||
| @property | ||
| def temperature_in_K(self) -> float: | ||
| """Returns the current temperature of the actor in K. | ||
|
|
@@ -164,3 +207,47 @@ def charge(self, duration_in_s: float): | |
| self = charge_model.charge(self, duration_in_s) | ||
|
|
||
| logger.debug(f"New battery level is {self.battery_level_in_Ws}") | ||
|
|
||
| @property | ||
| def attitude_in_rad(self): | ||
| """Returns the current attitude of the actor in radians. | ||
|
|
||
| Returns: | ||
| list[floats]: actor attitude in radians. | ||
| """ | ||
| if type(self._attitude_model._actor_attitude_in_rad) is np.ndarray: | ||
| return np.ndarray.tolist(self._attitude_model._actor_attitude_in_rad) | ||
| else: | ||
| return self._attitude_model._actor_attitude_in_rad | ||
|
|
||
| @property | ||
| def attitude_in_deg(self): | ||
| """Returns the current attitude of the actor in degrees. | ||
|
|
||
| Returns: | ||
| list[floats]: actor attitude in degrees. | ||
| """ | ||
| if type(self._attitude_model._actor_attitude_in_rad) is np.ndarray: | ||
| return np.ndarray.tolist(self._attitude_model._actor_attitude_in_rad * 180 / np.pi) | ||
| else: | ||
| return np.ndarray.tolist( | ||
| np.array(self._attitude_model._actor_attitude_in_rad) * 180 / np.pi | ||
| ) | ||
|
|
||
| @property | ||
| def pointing_vector(self): | ||
| """Returns the spacecraft pointing vector in the Earth-centered inertial frame. | ||
|
|
||
| Returns: | ||
| np.ndarray (x, y, z). | ||
| """ | ||
| return self._attitude_model._actor_pointing_vector_eci | ||
|
|
||
| @property | ||
| def angular_velocity(self): | ||
| """Returns the spacecraft angular velocity vector in the Earth-centered inertial frame. | ||
|
|
||
| Returns: | ||
| np.ndarray (owega_x, omega_y, omega_z). | ||
| """ | ||
| return self._attitude_model._actor_angular_velocity_eci | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Duplicate code of
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I removed it from the spacecraft_body_model, so you can access this from spacecraft actor.
GabrieleMeoni marked this conversation as resolved.
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| import trimesh | ||
|
|
||
|
|
||
| def create_body_mesh(vertices=None, faces=None, scale=1): | ||
| """Creates the mesh of the satellite. If no vertices input is given, it defaults to a cuboid scaled by the | ||
| scale value. The default without scale values is a cube with 1m sides. This uses the python module Trimesh. | ||
| Args: | ||
| vertices (list): List of all vertices of the mesh in terms of distance (in m) from origin of body frame. | ||
| Coordinates of the corners of the object. If not selected, it will default to a cube that can be scaled | ||
| by the scale. Uses Trimesh to create the mesh from this and the list of faces. | ||
| faces (list): List of the indexes of the vertices of a face. This builds the faces of the satellite by | ||
| defining the three vertices to form a triangular face. For a cuboid each face is split into two | ||
| triangles. Uses Trimesh to create the mesh from this and the list of vertices. | ||
| scale (float): Parameter to scale the cuboid by, defaults to 1. | ||
|
|
||
| Returns: | ||
| mesh: Trimesh mesh of the satellite | ||
| """ | ||
| if vertices is None: | ||
| # Defines the corners of the mesh, values are in meters, from the origin of the body frame. | ||
| vertices = [ | ||
| [-0.5, -0.5, -0.5], | ||
| [-0.5, -0.5, 0.5], | ||
| [-0.5, 0.5, -0.5], | ||
| [-0.5, 0.5, 0.5], | ||
| [0.5, -0.5, -0.5], | ||
| [0.5, -0.5, 0.5], | ||
| [0.5, 0.5, -0.5], | ||
| [0.5, 0.5, 0.5], | ||
| ] | ||
| # List of three vertices to form a triangular face of the satellite. | ||
| # Two triangular faces are used per side of the cuboid. | ||
| faces = [ | ||
| [0, 1, 3], | ||
| [0, 3, 2], | ||
| [0, 2, 6], | ||
| [0, 6, 4], | ||
| [1, 5, 3], | ||
| [3, 5, 7], | ||
| [2, 3, 7], | ||
| [2, 7, 6], | ||
| [4, 6, 7], | ||
| [4, 7, 5], | ||
| [0, 4, 1], | ||
| [1, 4, 5], | ||
| ] | ||
|
|
||
| # Set mesh | ||
| mesh = trimesh.Trimesh(vertices, faces).apply_scale(scale) | ||
|
|
||
| return mesh |
Uh oh!
There was an error while loading. Please reload this page.