C++ Module: spinningBodyOneDOFStateEffector
Executive Summary
The spinning body class is an instantiation of the state effector abstract class. The integrated test is validating the interaction between the spinning body module and the rigid body hub that it is attached to. In this case, a 1-DoF spinning body has an inertia tensor and is attached to the hub by a single degree of freedom axis. This module can represent multiple different effectors, such as a hinged solar panel, a reaction wheel or a single-gimbal. The spinning axis is fixed in the body frame and the effector is rigid, which means that its center of mass location does not move in the spinning frame S. An optional motor torque can be applied on the spinning axis, and the user can also lock the axis through a command.
Message Connection Descriptions
The following table lists all the module input and output messages. The module msg variable name is set by the user from python. The msg type contains a link to the message structure definition, while the description provides information on what this message is used for.
Msg Variable Name |
Msg Type |
Description |
|---|---|---|
spinningBodyOutMsg |
Output message containing the spinning body state angle and angle rate. |
|
motorTorqueInMsg |
(Optional) Motor torque for this module’s axis, read from |
|
motorLockInMsg |
(Optional) Lock command for this module’s axis, read from |
|
spinningBodyRefInMsg |
(Optional) Input message for prescribing the angle and angle rate. |
|
spinningBodyConfigLogOutMsg |
Output message containing the spinning body inertial position and attitude states. |
Detailed Module Description
A 1 DoF spinning body has 2 states: theta and thetaDot. The angle and angle rate can change due to the interaction with the hub, but also because of applied torques (control, spring and damper). The angle remains fixed and the angle rate is set to zero when the axis is locked.
Command Array Indexing
Each module instance reads only element [0] of its lock and motor torque messages.
For the spinning-body modules, array elements correspond to degrees of freedom within
one module; they are not selected by effectorID or by the order in which module
instances are added to the spacecraft. The shared message payloads use arrays sized by
MAX_EFF_CNT, but that capacity does not assign an element to each module instance.
Use a separate ArrayEffectorLockMsg for each OneDOF instance that needs independent
locking. If two instances subscribe to the same message, both read
effectorLockFlag[0]: [1, 0] locks both, and [0, 1] leaves both free to rotate.
The same rule applies to independent motor torque commands using
ArrayMotorTorqueMsg. Use 0 for a free axis and 1 for a locked axis.
Mathematical Modeling
See the following conference paper for a detailed description of this model.
Note
J. Vaz Carneiro, C. Allard and H. Schaub, “Rotating Rigid Body Dynamics Architecture for Spacecraft Simulation Software Implementation”, AAS Rocky Mountain GN&C Conference, Breckenridge, CO, Feb. 2–8, 2023
User Guide
This section is to outline the steps needed to setup a Spinning Body State Effector in Python using Basilisk.
Import the spinningBodyOneDOFStateEffector class:
from Basilisk.simulation import spinningBodyOneDOFStateEffector
Create an instantiation of a Spinning body:
spinningBody = spinningBodyOneDOFStateEffector.SpinningBodyOneDOFStateEffector()
Define all physical parameters for a Spinning Body. For example:
spinningBody.mass = 100.0 spinningBody.IPntSc_S = [[100.0, 0.0, 0.0], [0.0, 50.0, 0.0], [0.0, 0.0, 50.0]] spinningBody.dcm_S0B = [[-1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0]] spinningBody.r_ScS_S = [[0.5], [0.0], [1.0]] spinningBody.r_SB_B = [[1.5], [-0.5], [2.0]] spinningBody.sHat_S = [[0], [0], [1]]
(Optional) Define initial conditions of the effector. Default values are zero states:
spinningBody.thetaInit = 5 * macros.D2R spinningBody.thetaDotInit = 1 * macros.D2R
(Optional) Define spring and damper coefficients. Default values are zero states:
spinningBody.k = 1.0 spinningBody.c = 0.5
(Optional) Define a unique name for each state. If you have multiple spinning bodies, they each must have a unique name. If these names are not specified, then the default names are used which are incremented by the effector number:
spinningBody.nameOfThetaState = "spinningBodyTheta" spinningBody.nameOfThetaDotState = "spinningBodyThetaDot"
(Optional) Connect a command torque message:
cmdArray = messaging.ArrayMotorTorqueMsgPayload() cmdArray.motorTorque = [cmdTorque] # [Nm] cmdMsg = messaging.ArrayMotorTorqueMsg().write(cmdArray) spinningBody.motorTorqueInMsg.subscribeTo(cmdMsg)
(Optional) Connect an axis-locking message (0 means the axis is free to rotate and 1 locks the axis):
lockArray = messaging.ArrayEffectorLockMsgPayload() lockArray.effectorLockFlag = [1] lockMsg = messaging.ArrayEffectorLockMsg().write(lockArray) spinningBody.motorLockInMsg.subscribeTo(lockMsg)
(Optional) Connect an angle and angle rate reference message:
angleRef = messaging.HingedRigidBodyMsgPayload() angleRef.theta = thetaRef angleRef.thetaDot = thetaDotRef angleRefMsg = messaging.HingedRigidBodyMsg().write(angleRef) spinningBody.spinningBodyRefInMsg.subscribeTo(angleRefMsg)
The angular states of the body are created using an output message
spinningBodyOutMsg.The spinning body config log state output message is
spinningBodyConfigLogOutMsg.Add the effector to your spacecraft:
scObject.addStateEffector(spinningBody)
See C++ Module: spacecraft documentation on how to set up a spacecraft object.
Add the module to the task list:
unitTestSim.AddModelToTask(unitTaskName, spinningBody)
Locking Multiple Module Instances
For two configured OneDOF instances named solar_array1 and solar_array2, the
following example locks the first axis and leaves the second free to rotate:
from Basilisk.architecture import messaging
lock_payload1 = messaging.ArrayEffectorLockMsgPayload()
lock_payload1.effectorLockFlag = [1]
lock_msg1 = messaging.ArrayEffectorLockMsg().write(lock_payload1)
solar_array1.motorLockInMsg.subscribeTo(lock_msg1)
lock_payload2 = messaging.ArrayEffectorLockMsgPayload()
lock_payload2.effectorLockFlag = [0]
lock_msg2 = messaging.ArrayEffectorLockMsg().write(lock_payload2)
solar_array2.motorLockInMsg.subscribeTo(lock_msg2)
Keep both message objects available for the simulation. To change a lock command, update its payload and write it to the corresponding message again. Add both effectors to the spacecraft and to a simulation task as shown above so they process the commands.
Initialization and Reset
Attaching the effector to a spacecraft causes its configuration to be validated when the spacecraft registers
the effector states. Initialization normalizes sHat_S and rejects a zero spin axis, a non-rotation
dcm_S0B, a negative mass, or an invalid inertia tensor for a body with positive mass.
The spacecraft drives the effector dynamics. Add the effector to a task to process its optional torque, lock,
and reference inputs and to update its output messages through UpdateState().
When the effector is scheduled, its Reset() repeats the same validation and
normalization. Reset() does not reset the integrated angle or angle-rate states; those states receive their
configured initial values when they are registered with the spacecraft dynamics.
Hosting a Dynamic Effector
This effector supports the branching described in Advanced: Effector Module Branching, so a compatible dynamic effector can be carried by the spinning body rather than by the hub:
spinningBody.addDynamicEffector(childEffector)
This effector then makes its inertial position, velocity, attitude, and angular velocity available in place of the hub’s, and the child reads whichever of the four its model needs. Any geometry given to the child is expressed in that spinning body’s frame rather than the hub body frame. Both this effector and the child are still added to the task in the usual way.
Finite Configuration Values
All configured masses, spring and damping coefficients, initial angles and angular rates, position offsets, and inertia entries must be finite. This requirement also applies to inertia entries on massless bodies; the existing rules for inertia realizability remain unchanged. The frame rotation checks reject non-finite DCMs as well as improper rotations.
Spin axes must contain only finite components and have a norm strictly greater than 0.01.
Normalization scales the components before computing their norm, so very large finite axes
retain the correct direction. Repeated resets preserve integrated states and commands.
These checks run before state registration and from Reset(). A failed configuration check
raises BasiliskError before normalizing the spin axis or registering effector states.
-
class SpinningBodyOneDOFStateEffector : public StateEffector, public SysModel
- #include <spinningBodyOneDOFStateEffector.h>
spinning body state effector class
Public Functions
-
SpinningBodyOneDOFStateEffector()
Constructor.
This is the constructor, setting variables to default values
-
~SpinningBodyOneDOFStateEffector() override
Destructor.
This is the destructor, nothing to report here
-
void Reset(uint64_t CurrentClock) override
Method for reset.
This method validates the module configuration when the scheduler resets the model.
- Parameters:
CurrentClock – [ns] Time at which the reset occurs
-
void writeOutputStateMessages(uint64_t CurrentClock) override
Method for writing the output messages.
This method takes the computed theta states and outputs them to the messaging system.
- Parameters:
CurrentClock – [in] [ns] Current simulation time.
-
void UpdateState(uint64_t CurrentSimNanos) override
Method for updating information.
This method is used so that the simulation will ask SB to update messages
- Parameters:
CurrentSimNanos – [in] [ns] Current simulation time.
-
void registerStates(DynParamManager &statesIn) override
Method for registering the SB states.
This method allows the SB state effector to register its states: theta and thetaDot with the dynamic parameter manager
- Parameters:
statesIn – [inout] Dynamic parameter manager used to register states or properties.
-
void linkInStates(DynParamManager &states) override
Method for getting access to other states.
This method allows the SB state effector to have access to the hub states and gravity
- Parameters:
states – [in] Dynamic parameter manager containing the required states.
-
void addDynamicEffector(DynamicEffector *newDynamicEffector, int segment = 1) override
Method for adding attached dynamic effector.
This method attaches a dynamicEffector
- Parameters:
newDynamicEffector – the dynamic effector to be attached to the SB
segment – defaults to the only segment for 1DOF (base segment 1)
-
void registerProperties(DynParamManager &states) override
Method for registering the SB inertial properties.
This method registers the SB inertial properties with the dynamic parameter manager and links them into dependent dynamic effectors
- Parameters:
states – [inout] Dynamic parameter manager used to register states or properties.
-
void linkInPrescribedMotionProperties(DynParamManager &states) override
Method for getting access to prescribed motion properties.
This method is used to link prescribed motion properties
- Parameters:
states – [in] Dynamic parameter manager containing the required properties.
-
void updateContributions(double integTime, BackSubMatrices &backSubContr, Eigen::MRPd sigma_BN, Eigen::Vector3d omega_BN_B, Eigen::Vector3d g_N) override
Method for Backsubstitution contributions.
This method allows the SB state effector to give its contributions to the matrices needed for the back-sub method
- Parameters:
integTime – [in] [s] Current integration time.
backSubContr – [inout] Backsubstitution contributions.
sigma_BN – [in] Hub attitude relative to the inertial frame.
omega_BN_B – [in] [rad/s] Hub angular velocity expressed in body-frame components.
g_N – [in] [m/s^2] Gravitational acceleration expressed in inertial-frame components.
-
void computeDerivatives(double integTime, Eigen::Vector3d rDDot_BN_N, Eigen::Vector3d omegaDot_BN_B, Eigen::MRPd sigma_BN) override
Method for SB to compute its derivatives.
This method is used to find the derivatives for the SB stateEffector: thetaDDot and the kinematic derivative
- Parameters:
integTime – [in] [s] Current integration time.
rDDot_BN_N – [in] [m/s^2] Hub translational acceleration expressed in inertial-frame components.
omegaDot_BN_B – [in] [rad/s^2] Hub angular acceleration expressed in body-frame components.
sigma_BN – [in] Hub attitude relative to the inertial frame.
-
void updateEffectorMassProps(double integTime) override
Method for giving the s/c the HRB mass props and prop rates.
This method allows the SB state effector to provide its contributions to the mass props and mass prop rates of the spacecraft
- Parameters:
integTime – [in] [s] Current integration time.
-
void updateEnergyMomContributions(double integTime, Eigen::Vector3d &rotAngMomPntCContr_B, double &rotEnergyContr, Eigen::Vector3d omega_BN_B) override
Method for computing energy and momentum for SBs.
This method is for calculating the contributions of the SB state effector to the energy and momentum of the spacecraft
- Parameters:
integTime – [in] [s] Current integration time.
rotAngMomPntCContr_B – [inout] [kg*m^2/s] Rotational angular momentum contribution.
rotEnergyContr – [inout] [J] Rotational energy contribution.
omega_BN_B – [in] [rad/s] Hub angular velocity expressed in body-frame components.
-
void prependSpacecraftNameToStates() override
Method used for multiple spacecraft.
This method prepends the name of the spacecraft for multi-spacecraft simulations.
-
void computeSpinningBodyInertialStates()
Method for computing the SB’s states.
This method computes the spinning body states relative to the inertial frame
-
void addPrescribedMotionCouplingContributions(BackSubMatrices &backSubContr) override
Method for adding coupling contributions for state effector branching on prescribed motion.
Add prescribed-motion coupling terms.
- Parameters:
backSubContr – [inout] Backsubstitution contributions.
Public Members
-
double mass = 1.0
[kg] mass of spinning body
-
double k = 0.0
[N-m/rad] torsional spring constant
-
double c = 0.0
[N-m-s/rad] rotational damping coefficient
-
double thetaInit = 0.0
[rad] initial spinning body angle
-
double thetaDotInit = 0.0
[rad/s] initial spinning body angle rate
-
std::string nameOfThetaState
identifier for the theta state data container
-
std::string nameOfThetaDotState
identifier for the thetaDot state data container
-
std::string nameOfInertialPositionProperty
identifier for the inertial position property
-
std::string nameOfInertialVelocityProperty
identifier for the inertial velocity property
-
std::string nameOfInertialAttitudeProperty
identifier for the inertial attitude property
-
std::string nameOfInertialAngVelocityProperty
identifier for the inertial angular velocity property
-
Eigen::Vector3d r_SB_B = {0.0, 0.0, 0.0}
[m] vector pointing from body frame B origin to spinning frame S origin in B frame components
-
Eigen::Vector3d r_ScS_S = {0.0, 0.0, 0.0}
[m] vector pointing from spinning frame S origin to point Sc (center of mass of the spinner) in S frame components
-
Message<HingedRigidBodyMsgPayload> spinningBodyOutMsg
state output message
-
Message<SCStatesMsgPayload> spinningBodyConfigLogOutMsg
spinning body state config log message
-
ReadFunctor<ArrayMotorTorqueMsgPayload> motorTorqueInMsg
(optional) motor torque input message
-
ReadFunctor<ArrayEffectorLockMsgPayload> motorLockInMsg
(optional) motor lock flag input message
-
ReadFunctor<HingedRigidBodyMsgPayload> spinningBodyRefInMsg
(optional) spinning body reference input message name
-
std::vector<DynamicEffector*> dynEffectors
Vector of dynamic effectors attached.
Private Functions
-
void validateConfiguration()
Validate and normalize the user-supplied configuration.
Validate finite configuration values and normalize the configured spin axes.
Private Members
-
double u = 0.0
[N-m] optional motor torque
-
int lockFlag = 0
[] flag for locking the rotation axis
-
double thetaRef = 0.0
[rad] spinning body reference angle
-
double thetaDotRef = 0.0
[rad] spinning body reference angle rate
-
double cTheta = 0.0
scalar term for Backsubstitution
-
double mTheta = 0.0
auxiliary term for Backsubstitution
-
Eigen::Vector3d r_ScS_B = {0.0, 0.0, 0.0}
[m] vector pointing from spinning frame S origin to point Sc in B frame components
-
Eigen::Vector3d r_ScB_B = {0.0, 0.0, 0.0}
[m] vector pointing from body frame B origin to point Sc in B frame components.
-
Eigen::Vector3d omega_SB_B = {0.0, 0.0, 0.0}
[rad/s] angular velocity of the S frame wrt the B frame in B frame components.
-
Eigen::Vector3d omega_BN_B = {0.0, 0.0, 0.0}
[rad/s] angular velocity of the B frame wrt the N frame in B frame components.
-
Eigen::Vector3d omega_SN_B = {0.0, 0.0, 0.0}
[rad/s] angular velocity of the S frame wrt the N frame in B frame components.
-
Eigen::Vector3d r_ScN_N = {0.0, 0.0, 0.0}
[m] position vector of spinning body center of mass Sc relative to the inertial frame origin N
-
Eigen::Vector3d v_ScN_N = {0.0, 0.0, 0.0}
[m/s] inertial velocity vector of Sc relative to inertial frame
-
Eigen::MatrixXd *r_SN_N
[m] position vector of spinning body origin S relative to the inertial frame origin N
-
double theta = 0.0
[rad] spinning body angle
-
double thetaDot = 0.0
[rad/s] spinning body angle rate
-
Eigen::MatrixXd *inertialPositionProperty = nullptr
[m] r_N inertial position relative to system spice zeroBase/refBase
Private Static Attributes
-
static uint64_t effectorID = 1
[] ID number of this panel
-
SpinningBodyOneDOFStateEffector()