From 74b3aa413aea3129d7a4d080bf5b03815739d574 Mon Sep 17 00:00:00 2001 From: Moanalengkeek <69005558+Moanalengkeek@users.noreply.github.com> Date: Fri, 12 Jan 2024 13:49:33 +0100 Subject: [PATCH 1/3] Changes originally made in a separate fork --- environment.yml | 1 + paseos/actors/actor_builder.py | 40 +++++++++ paseos/geometric_model/geometric_model.py | 100 ++++++++++++++++++++++ requirements.txt | 3 +- setup.py | 1 + 5 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 paseos/geometric_model/geometric_model.py diff --git a/environment.yml b/environment.yml index 4a6c489..8fb1b7a 100644 --- a/environment.yml +++ b/environment.yml @@ -18,3 +18,4 @@ dependencies: - sphinx_rtd_theme # for docs - toml>=0.10.2 # core non-optional dependency - tqdm>=4.64.1 # core non-optional dependency + - trimesh>=4.0.7 # for geometric model \ No newline at end of file diff --git a/paseos/actors/actor_builder.py b/paseos/actors/actor_builder.py index 1a53532..4cddae4 100644 --- a/paseos/actors/actor_builder.py +++ b/paseos/actors/actor_builder.py @@ -13,6 +13,7 @@ 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 class ActorBuilder: @@ -305,6 +306,45 @@ def set_position(actor: BaseActor, position: list): actor._position = position logger.debug(f"Setting position {position} on actor {actor}") + @staticmethod + def set_geometric_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 + 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 + 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 + """ + assert mass > 0, "Mass is > 0" + + actor._mass = mass + geometric_model = GeometricModel( + local_actor=actor, + 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 + + + @staticmethod def set_power_devices( actor: SpacecraftActor, diff --git a/paseos/geometric_model/geometric_model.py b/paseos/geometric_model/geometric_model.py new file mode 100644 index 0000000..a5c0509 --- /dev/null +++ b/paseos/geometric_model/geometric_model.py @@ -0,0 +1,100 @@ +from loguru import logger +import trimesh + + +class GeometricModel: + """This model describes the geometry of the spacecraft + Currently it assumes the spacecraft to be a cuboid shape, with width, length and height + """ + + _actor = None + _actor_mesh = None + _actor_center_of_gravity = None + _actor_moment_of_inertia = None + + def __init__( + self, local_actor, actor_mass, vertices=None, faces=None, scale=1 + ) -> None: + """Describes the geometry of the spacecraft, and outputs relevant parameters related to the spacecraft body. + If no vertices or faces are provided, defaults to a cube with unit length sides. This is in the spacecraft body + reference frame, and can be transformed to the inertial/PASEOS reference frame using the transformations in the + attitude model + + Args: + local_actor (SpacecraftActor): Actor to model. + actor_mass (float): Actor's mass 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 + 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 + """ + logger.trace("Initializing cuboid geometrical model.") + + self._actor = local_actor + self._actor_mass = actor_mass + self.vertices = vertices + self.faces = faces + self.scale = scale + + def set_mesh(self): + """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. + + Returns: + mesh: Trimesh mesh of the satellite + """ + if self.vertices is None: + self.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], + ] # defines the corners of the mesh, values are in meters, from the origin of the body frame. + self.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], + ] # List of three vertices to form a triangular face of the satellite. Two triangular faces are used + # per side of the cuboid + mesh = trimesh.Trimesh(self.vertices, self.faces) + self._actor_mesh = mesh.apply_scale(self.scale) # Scales the mesh by the scale factor + return self._actor_mesh + + @property + def find_moment_of_inertia(self): + """Gives the moment of inertia of the actor, assuming constant density + + Returns: + np.array: Mass moments of inertia for the actor + + I is the moment of inertia, in the form of [[Ixx Ixy Ixz] + [Iyx Iyy Iyx] + [Izx Izy Izz]] + """ + self._actor_moment_of_inertia = self._actor_mesh.moment_inertia + return self._actor_moment_of_inertia + + def find_center_of_gravity(self): + """Gives the volumetric center of mass of the actor. + + Returns: + np.array: Coordinates of the center of gravity of the mesh + """ + self._actor_center_of_gravity = self._actor_mesh.center_mass + return self._actor_center_of_gravity \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 6ec5b86..9311acd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,4 +7,5 @@ pyquaternion>=0.9.9 scikit-spatial>=6.5.0 skyfield>=1.45 toml>=0.10.2 -tqdm>=4.64.1 \ No newline at end of file +tqdm>=4.64.1 +trimesh>=4.0.7 \ No newline at end of file diff --git a/setup.py b/setup.py index 467eab7..b6602ed 100644 --- a/setup.py +++ b/setup.py @@ -22,6 +22,7 @@ "skyfield>=1.45", "toml>=0.10.2", "tqdm>=4.64.1", + "trimesh>=4.0.7", ], classifiers=[ "Development Status :: 3 - Alpha", From 785ef48b12aebc5aea73b30a0310af7dde5d6f5b Mon Sep 17 00:00:00 2001 From: Gabriele Meoni Date: Fri, 12 Jan 2024 14:57:13 +0100 Subject: [PATCH 2/3] Fixing code to match CI/CD requirements. --- paseos/actors/actor_builder.py | 15 ++------------- paseos/geometric_model/geometric_model.py | 12 +++++------- 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/paseos/actors/actor_builder.py b/paseos/actors/actor_builder.py index 4cddae4..71c6b8c 100644 --- a/paseos/actors/actor_builder.py +++ b/paseos/actors/actor_builder.py @@ -308,12 +308,7 @@ def set_position(actor: BaseActor, position: list): @staticmethod def set_geometric_model( - actor: SpacecraftActor, - mass: float, - vertices=None, - faces=None, - scale: float = 1 - + 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 @@ -334,17 +329,11 @@ def set_geometric_model( actor._mass = mass geometric_model = GeometricModel( - local_actor=actor, - actor_mass=mass, - vertices=vertices, - faces=faces, - scale=scale + local_actor=actor, 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 - - @staticmethod def set_power_devices( actor: SpacecraftActor, diff --git a/paseos/geometric_model/geometric_model.py b/paseos/geometric_model/geometric_model.py index a5c0509..336ac1a 100644 --- a/paseos/geometric_model/geometric_model.py +++ b/paseos/geometric_model/geometric_model.py @@ -12,9 +12,7 @@ class GeometricModel: _actor_center_of_gravity = None _actor_moment_of_inertia = None - def __init__( - self, local_actor, actor_mass, vertices=None, faces=None, scale=1 - ) -> None: + def __init__(self, local_actor, actor_mass, vertices=None, faces=None, scale=1) -> None: """Describes the geometry of the spacecraft, and outputs relevant parameters related to the spacecraft body. If no vertices or faces are provided, defaults to a cube with unit length sides. This is in the spacecraft body reference frame, and can be transformed to the inertial/PASEOS reference frame using the transformations in the @@ -56,7 +54,7 @@ def set_mesh(self): [0.5, -0.5, 0.5], [0.5, 0.5, -0.5], [0.5, 0.5, 0.5], - ] # defines the corners of the mesh, values are in meters, from the origin of the body frame. + ] # defines the corners of the mesh, values are in meters, from the origin of the body frame. self.faces = [ [0, 1, 3], [0, 3, 2], @@ -70,10 +68,10 @@ def set_mesh(self): [4, 7, 5], [0, 4, 1], [1, 4, 5], - ] # List of three vertices to form a triangular face of the satellite. Two triangular faces are used + ] # List of three vertices to form a triangular face of the satellite. Two triangular faces are used # per side of the cuboid mesh = trimesh.Trimesh(self.vertices, self.faces) - self._actor_mesh = mesh.apply_scale(self.scale) # Scales the mesh by the scale factor + self._actor_mesh = mesh.apply_scale(self.scale) # Scales the mesh by the scale factor return self._actor_mesh @property @@ -97,4 +95,4 @@ def find_center_of_gravity(self): np.array: Coordinates of the center of gravity of the mesh """ self._actor_center_of_gravity = self._actor_mesh.center_mass - return self._actor_center_of_gravity \ No newline at end of file + return self._actor_center_of_gravity From 199040d43d483f237a0c1cca012b63092f9c299e Mon Sep 17 00:00:00 2001 From: Gabriele Meoni Date: Fri, 12 Jan 2024 15:05:42 +0100 Subject: [PATCH 3/3] Fixing commenting style for consistency. --- paseos/actors/actor_builder.py | 6 +++--- paseos/geometric_model/geometric_model.py | 24 +++++++++++++---------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/paseos/actors/actor_builder.py b/paseos/actors/actor_builder.py index 71c6b8c..17d022a 100644 --- a/paseos/actors/actor_builder.py +++ b/paseos/actors/actor_builder.py @@ -316,14 +316,14 @@ def set_geometric_model( Args: actor (SpacecraftActor): Actor to update. - mass (float): Mass of the spacecraft in kg + 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 + 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 + scale (float): Parameter to scale the cuboid by, defaults to 1. """ assert mass > 0, "Mass is > 0" diff --git a/paseos/geometric_model/geometric_model.py b/paseos/geometric_model/geometric_model.py index 336ac1a..7cd9216 100644 --- a/paseos/geometric_model/geometric_model.py +++ b/paseos/geometric_model/geometric_model.py @@ -13,10 +13,10 @@ class GeometricModel: _actor_moment_of_inertia = None def __init__(self, local_actor, actor_mass, vertices=None, faces=None, scale=1) -> None: - """Describes the geometry of the spacecraft, and outputs relevant parameters related to the spacecraft body. + """Describes the geometry of the spacecraft and outputs relevant parameters related to the spacecraft body. If no vertices or faces are provided, defaults to a cube with unit length sides. This is in the spacecraft body - reference frame, and can be transformed to the inertial/PASEOS reference frame using the transformations in the - attitude model + reference frame and can be transformed to the inertial/PASEOS reference frame by using the transformations in the + attitude model. Args: local_actor (SpacecraftActor): Actor to model. @@ -27,7 +27,7 @@ def __init__(self, local_actor, actor_mass, vertices=None, faces=None, scale=1) 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 + scale (float): Parameter to scale the cuboid by, defaults to 1. """ logger.trace("Initializing cuboid geometrical model.") @@ -45,6 +45,7 @@ def set_mesh(self): mesh: Trimesh mesh of the satellite """ if self.vertices is None: + # Defines the corners of the mesh, values are in meters, from the origin of the body frame. self.vertices = [ [-0.5, -0.5, -0.5], [-0.5, -0.5, 0.5], @@ -54,7 +55,9 @@ def set_mesh(self): [0.5, -0.5, 0.5], [0.5, 0.5, -0.5], [0.5, 0.5, 0.5], - ] # defines the corners of the mesh, values are in meters, from the origin of the body frame. + ] + # List of three vertices to form a triangular face of the satellite. + # Two triangular faces are used per side of the cuboid. self.faces = [ [0, 1, 3], [0, 3, 2], @@ -68,15 +71,16 @@ def set_mesh(self): [4, 7, 5], [0, 4, 1], [1, 4, 5], - ] # List of three vertices to form a triangular face of the satellite. Two triangular faces are used - # per side of the cuboid + ] + mesh = trimesh.Trimesh(self.vertices, self.faces) - self._actor_mesh = mesh.apply_scale(self.scale) # Scales the mesh by the scale factor + # Scales the mesh by the scale factor. + self._actor_mesh = mesh.apply_scale(self.scale) return self._actor_mesh @property def find_moment_of_inertia(self): - """Gives the moment of inertia of the actor, assuming constant density + """Gives the moment of inertia of the actor, assuming constant density. Returns: np.array: Mass moments of inertia for the actor @@ -92,7 +96,7 @@ def find_center_of_gravity(self): """Gives the volumetric center of mass of the actor. Returns: - np.array: Coordinates of the center of gravity of the mesh + np.array: Coordinates of the center of gravity of the mesh. """ self._actor_center_of_gravity = self._actor_mesh.center_mass return self._actor_center_of_gravity