C++ Module: spinningBodyTwoDOFStateEffector
Executive Summary
The two-degree-of-freedom spinning body class is an instantiation of the state effector abstract class. The integrated test is validating the interaction between the 2-DoF spinning body module and the rigid body hub that it is attached to. In this case, a 2-DoF spinning body system has two masses and two inertia tensors. The lower axis is attached to the hub and the upper axis is attached to the lower body. This module can represent multiple different effectors, such as a dual-hinged solar array, a control moment gyroscope or a dual-gimbal. A spring and damper can be included in each axis, and an optional motor torque can be applied on each spinning axis.
Nominally, two rigid bodies can be defined, which would represent a chain of 1D rotary joints. However, by setting the mass and the inertia of the lower spinning body to 0, the module can simulate a single rigid component rotating about two axis instead.
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 |
|---|---|---|
spinningBodyOutMsgs |
Output vector of messages containing the spinning body state angle and angle rate. |
|
motorTorqueInMsg |
(Optional) Motor torques for this module’s two axes, read from |
|
motorLockInMsg |
(Optional) Lock commands for this module’s two axes, read from |
|
spinningBodyRefInMsgs |
(Optional) Input array of messages for prescribing the angles and angle rates. |
|
spinningBodyConfigLogOutMsgs |
Output vector of messages containing the spinning body inertial position and attitude states. |
Detailed Module Description
A 2 DoF spinning body has 4 states: theta1, theta2, theta1Dot and theta2Dot.
Command Array Indexing
One lock message controls both degrees of freedom in this module.
effectorLockFlag[0] controls the first axis (theta1), and
effectorLockFlag[1] controls the second axis (theta2). Use 0 for a free axis
and 1 for a locked axis. For example, [1, 0] locks the first axis and leaves
the second free to rotate. Motor torque commands use the same ordering in
motorTorque[0] and motorTorque[1]. Remaining array elements are ignored.
These indexes identify degrees of freedom within a single module, independently of
effectorID and the order in which module instances are added to the spacecraft.
Use separate lock and torque messages for module instances that need independent
commands. Instances sharing a message receive the same pair of axis commands. See
C++ Module: spinningBodyOneDOFStateEffector for an example of independent lock messages.
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 2 DoF State Effector in Python using Basilisk.
Import the spinningBodyTwoDOFStateEffector class:
from Basilisk.simulation import spinningBodyTwoDOFStateEffector
Create an instantiation of a Spinning body:
spinningBody = spinningBodyTwoDOFStateEffector.SpinningBodyTwoDOFStateEffector()
Define all physical parameters for both spinning bodies. For example:
spinningBody.mass1 = 100.0 spinningBody.mass2 = 50.0 spinningBody.IS1PntSc1_S1 = [[100.0, 0.0, 0.0], [0.0, 50.0, 0.0], [0.0, 0.0, 50.0]] spinningBody.IS2PntSc2_S2 = [[50.0, 0.0, 0.0], [0.0, 30.0, 0.0], [0.0, 0.0, 40.0]] spinningBody.dcm_S10B = [[-1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0]] spinningBody.dcm_S20S1 = [[0.0, -1.0, 0.0], [0.0, .0, -1.0], [1.0, 0.0, 0.0]] spinningBody.r_Sc1S1_S1 = [[2.0], [-0.5], [0.0]] spinningBody.r_Sc2S2_S2 = [[1.0], [0.0], [-1.0]] spinningBody.r_S1B_B = [[-2.0], [0.5], [-1.0]] spinningBody.r_S2S1_S1 = [[0.5], [-1.5], [-0.5]] spinningBody.s1Hat_S1 = [[0], [0], [1]] spinningBody.s2Hat_S2 = [[0], [-1], [0]]
(Optional) Define initial conditions of the effector. Default values are zero states:
spinningBody.theta1Init = 0 * macros.D2R spinningBody.theta1DotInit = 0.1 * macros.D2R spinningBody.theta2Init = 5 * macros.D2R spinningBody.theta2DotInit = -0.5 * macros.D2R
(Optional) Define spring and damper coefficients. Default values are zero states:
spinningBody.k1 = 1.0 spinningBody.c1 = 0.1 spinningBody.k2 = 2.0 spinningBody.c2 = 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.nameOfTheta1State = "spinningBodyTheta1" spinningBody.nameOfTheta1DotState = "spinningBodyTheta1Dot" spinningBody.nameOfTheta2State = "spinningBodyTheta2" spinningBody.nameOfTheta2DotState = "spinningBodyTheta2Dot"
(Optional) Connect a command torque message:
cmdArray = messaging.ArrayMotorTorqueMsgPayload() cmdArray.motorTorque = [cmdTorque1, cmdTorque2] # [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, 0] lockMsg = messaging.ArrayEffectorLockMsg().write(lockArray) spinningBody.motorLockInMsg.subscribeTo(lockMsg)
(Optional) Connect angle and angle rate reference messages:
angle1Ref = messaging.HingedRigidBodyMsgPayload() angle1Ref.theta = theta1Ref angle1Ref.thetaDot = theta1DotRef angle1RefMsg = messaging.HingedRigidBodyMsg().write(angle1Ref) spinningBody.spinningBodyRefInMsgs[0].subscribeTo(angle1RefMsg) angle2Ref = messaging.HingedRigidBodyMsgPayload() angle2Ref.theta = theta2Ref angle2Ref.thetaDot = theta2DotRef angle2RefMsg = messaging.HingedRigidBodyMsg().write(angle2Ref) spinningBody.spinningBodyRefInMsgs[1].subscribeTo(angle2RefMsg)
The angular states of the body are created using an output vector of messages
spinningBodyOutMsgs.The spinning body config log state output messages is
spinningBodyConfigLogOutMsgs.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)
Initialization and Reset
Attaching the effector to a spacecraft causes its configuration to be validated when the spacecraft registers the effector states. Initialization normalizes both spin axes and rejects a zero spin axis, an invalid initial rotation matrix, a negative body 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 angles 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 one of the spinning bodies rather than by the hub:
spinningBodyEffector.addDynamicEffector(childEffector, segment)
Here segment is the one-based spinning body number, counting outward from the hub, so 1 is the
spinning body attached to the hub.
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
The combined body mass must remain finite. 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 either spin axis or registering effector states.
-
class SpinningBodyTwoDOFStateEffector : public StateEffector, public SysModel
- #include <spinningBodyTwoDOFStateEffector.h>
spinning body state effector class
Public Functions
-
SpinningBodyTwoDOFStateEffector()
Constructor.
This is the constructor, setting variables to default values
-
~SpinningBodyTwoDOFStateEffector()
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) override
Method for adding attached dynamic effector.
This method attaches a dynamicEffector to the specified SB
- Parameters:
newDynamicEffector – the dynamic effector to be attached to the SB
segment – the integer number segment to be attached to (inner segment=1, outer segment=2)
-
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 mass1 = 0.0
[kg] mass of lower spinning body (can be 0)
-
double mass2 = 1.0
[kg] mass of upper spinning body
-
double k1 = 0.0
[N-m/rad] torsional spring constant for first rotation axis
-
double k2 = 0.0
[N-m/rad] torsional spring constant for second rotation axis
-
double c1 = 0.0
[N-m-s/rad] rotational damping coefficient for first rotation axis
-
double c2 = 0.0
[N-m-s/rad] rotational damping coefficient for second rotation axis
-
double theta1Init = 0.0
[rad] initial first axis angle
-
double theta1DotInit = 0.0
[rad/s] initial first axis angle rate
-
double theta2Init = 0.0
[rad] initial second axis angle
-
double theta2DotInit = 0.0
[rad/s] initial second axis angle rate
-
std::string nameOfTheta1State
identifier for the theta1 state data container
-
std::string nameOfTheta1DotState
identifier for the thetaDot1 state data container
-
std::string nameOfTheta2State
identifier for the theta2 state data container
-
std::string nameOfTheta2DotState
identifier for the thetaDot2 state data container
-
std::string nameOfInertialPositionProperty1
identifier for the lower spinning body inertial position property
-
std::string nameOfInertialVelocityProperty1
identifier for the lower spinning body inertial velocity property
-
std::string nameOfInertialAttitudeProperty1
identifier for the lower spinning body inertial attitude property
-
std::string nameOfInertialAngVelocityProperty1
identifier for the lower spinning body inertial angular velocity property
-
std::string nameOfInertialPositionProperty2
identifier for the upper spinning body inertial position property
-
std::string nameOfInertialVelocityProperty2
identifier for the upper spinning body inertial velocity property
-
std::string nameOfInertialAttitudeProperty2
identifier for the upper spinning body inertial attitude property
-
std::string nameOfInertialAngVelocityProperty2
identifier for the upper spinning body inertial angular velocity property
-
Eigen::Vector3d r_S1B_B = {0.0, 0.0, 0.0}
[m] vector pointing from body frame B origin to lower spinning frame S1 origin in B frame components
-
Eigen::Vector3d r_S2S1_S1 = {0.0, 0.0, 0.0}
[m] vector pointing from lower spinning frame S1 origin to upper spinning frame S2 origin in S1 frame components
-
Eigen::Vector3d r_Sc1S1_S1 = {0.0, 0.0, 0.0}
[m] vector pointing from lower spinning frame S1 origin to point Sc1 (center of mass of the lower spinner) in S1 frame components
-
Eigen::Vector3d r_Sc2S2_S2 = {0.0, 0.0, 0.0}
[m] vector pointing from upper spinning frame S2 origin to point Sc2 (center of mass of the upper spinner) in S2 frame components
-
Eigen::Matrix3d IS1PntSc1_S1
[kg-m^2] Inertia of lower spinning body about point Sc1 in S1 frame components
-
Eigen::Matrix3d IS2PntSc2_S2
[kg-m^2] Inertia of upper spinning body about point Sc2 in S2 frame components
-
std::vector<Message<HingedRigidBodyMsgPayload>*> spinningBodyOutMsgs{new Message<HingedRigidBodyMsgPayload>, new Message<HingedRigidBodyMsgPayload>}
vector of state output messages
-
std::vector<Message<SCStatesMsgPayload>*> spinningBodyConfigLogOutMsgs{new Message<SCStatesMsgPayload>, new Message<SCStatesMsgPayload>}
vector of spinning body state config log messages
-
ReadFunctor<ArrayMotorTorqueMsgPayload> motorTorqueInMsg
(optional) motor torque input message name
-
ReadFunctor<ArrayEffectorLockMsgPayload> motorLockInMsg
(optional) motor lock input message name
-
std::vector<ReadFunctor<HingedRigidBodyMsgPayload>> spinningBodyRefInMsgs{ReadFunctor<HingedRigidBodyMsgPayload>(), ReadFunctor<HingedRigidBodyMsgPayload>()}
(optional) vector of spinning body reference input messages
-
std::vector<DynamicEffector*> dynEffectors
Vector of dynamic effectors attached.
Private Functions
-
void validateConfiguration()
Validate finite configuration values and normalize the configured spin axes.
Private Members
-
double u1 = 0.0
[N-m] optional motor torque for first axis
-
double u2 = 0.0
[N-m] optional motor torque for second axis
-
int lockFlag1 = 0
[] flag for locking the first rotation axis
-
int lockFlag2 = 0
[] flag for locking the second rotation axis
-
double theta1Ref = 0.0
[rad] spinning body reference angle
-
double theta1DotRef = 0.0
[rad] spinning body reference angle rate
-
double theta2Ref = 0.0
[rad] spinning body reference angle
-
double theta2DotRef = 0.0
[rad] spinning body reference angle rate
-
double mass = 1.0
[kg] mass of the spinner system
-
Eigen::Vector3d r_Sc1S1_B = {0.0, 0.0, 0.0}
[m] vector pointing from lower spinning frame S1 origin to point Sc1 in B frame components
-
Eigen::Vector3d r_Sc1B_B = {0.0, 0.0, 0.0}
[m] vector pointing from body frame B origin to point Sc1 in B frame components.
-
Eigen::Vector3d r_Sc2S2_B = {0.0, 0.0, 0.0}
[m] vector pointing from upper spinning frame S2 origin to point Sc2 in B frame components
-
Eigen::Vector3d r_S2S1_B = {0.0, 0.0, 0.0}
[m] vector pointing from lower spinning frame S1 origin to upper spinning frame S2 origin in B frame components
-
Eigen::Vector3d r_Sc2S1_B = {0.0, 0.0, 0.0}
[m] vector pointing from lower spinning frame S1 origin to point Sc2 in B frame components
-
Eigen::Vector3d r_Sc2B_B = {0.0, 0.0, 0.0}
[m] vector pointing from body frame B origin to point Sc2 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 (center of mass of the spinner system) in B frame components.
-
Eigen::Vector3d omega_S1B_B = {0.0, 0.0, 0.0}
[rad/s] angular velocity of the S1 frame wrt the B frame in B frame components
-
Eigen::Vector3d omega_S2S1_B = {0.0, 0.0, 0.0}
[rad/s] angular velocity of the S2 frame wrt the S1 frame in B frame components
-
Eigen::Vector3d omega_S2B_B = {0.0, 0.0, 0.0}
[rad/s] angular velocity of the S2 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_S1N_B = {0.0, 0.0, 0.0}
[rad/s] angular velocity of the S1 frame wrt the N frame in B frame components
-
Eigen::Vector3d omega_S2N_B = {0.0, 0.0, 0.0}
[rad/s] angular velocity of the S2 frame wrt the N frame in B frame components
-
Eigen::Matrix3d IS1PntSc1_B
[kg-m^2] inertia of lower spinning body about point Sc1 in B frame components
-
Eigen::Matrix3d IS2PntSc2_B
[kg-m^2] inertia of upper spinning body about point Sc2 in B frame components
-
Eigen::Matrix3d IPrimeS1PntSc1_B
[kg-m^2] body frame time derivative of inertia of inertia of lower spinning body about point Sc1 in B frame components
-
Eigen::Matrix3d IPrimeS2PntSc2_B
[kg-m^2] body frame time derivative of inertia of inertia of upper spinning body about point Sc2 in B frame components
-
Eigen::Vector3d r_Sc1N_N = {0.0, 0.0, 0.0}
[m] position vector of lower spinning body center of mass Sc1 relative to the inertial frame origin N
-
Eigen::Vector3d r_Sc2N_N = {0.0, 0.0, 0.0}
[m] position vector of upper spinning body center of mass Sc2 relative to the inertial frame origin N
-
Eigen::Vector3d v_Sc1N_N = {0.0, 0.0, 0.0}
[m/s] inertial velocity vector of Sc1 relative to inertial frame
-
Eigen::Vector3d v_Sc2N_N = {0.0, 0.0, 0.0}
[m/s] inertial velocity vector of Sc2 relative to inertial frame
-
Eigen::MatrixXd *r_S1N_N
[m] position vector of lower spinning body origin S1 relative to the inertial frame origin N
-
Eigen::MatrixXd *r_S2N_N
[m] position vector of upper spinning body origin S2 relative to the inertial frame origin N
-
double theta1 = 0.0
[rad] first axis angle
-
double theta1Dot = 0.0
[rad/s] first axis angle rate
-
double theta2 = 0.0
[rad] second axis angle
-
double theta2Dot = 0.0
[rad/s] second axis 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
-
SpinningBodyTwoDOFStateEffector()