C++ Module: linearTranslationNDOFStateEffector

Executive Summary

The N-DoF linear translation body class is an instantiation of the state effector abstract class with \(N\) degrees of freedom. The integrated test is validating the interaction between the linear translation body module and the rigid body hub that it is attached to. In this case, a 4-DoF linear translation body has an inertia tensor and is attached to the hub by four single-degree-of-freedom axes. Each translating axis is fixed in the parent’s body frame and each body is rigid, which means that its center of mass location does not move in the \(F\) frame. An optional motor force can be applied on each translating axis, and the user can also lock an axis through a command. Moreover, the user can input a displacement reference that the effector will track through a spring and damper.

Nominally, each degree of freedom corresponds to an additional rigid body link. However, by setting the mass and the inertia of a body to 0, several single axis bodies can compose one multiple degree of freedom joint 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.

linearTranslationNDOFStateEffector module input and output messages

Module I/O Messages

Msg Variable Name

Msg Type

Description

translatingBodyOutMsgs

LinearTranslationRigidBodyMsgPayload

Output vector of messages containing the linear translation body state displacement and displacement rate.

motorForceInMsg

ArrayMotorForceMsgPayload

(Optional) Input message of the motor force value for every axis.

motorLockInMsg

ArrayEffectorLockMsgPayload

(Optional) Input message for locking each axis.

translatingBodyRefInMsgs

LinearTranslationRigidBodyMsgPayload

(Optional) Input vector of messages for prescribing the displacement and displacement rate.

translatingBodyConfigLogOutMsgs

SCStatesMsgPayload

Output vector of messages containing the translating body inertial states. The position and velocity are those of the body center of mass, and the attitude and angular velocity are those of the body frame F.

Detailed Module Description

For each degree of freedom, the user must create a translating body inside the \(N\)-DoF module. Each body represents a link and has 2 states: rho and rhoDot. The displacement and displacement rate can change due to the interaction with the hub, but also because of applied forces (control, spring and damper). The displacement remains fixed and the displacement rate is set to zero when the axis is locked.

Mathematical Modeling

See the following conference paper for a detailed description of this model.

Note

P. Johnson and J. Vaz Carneiro, “Backsubstitution Method For Spacecraft With Generally Translating Appendages,” AAS Astrodynamics Specialist Conference, Broomfield, CO, Aug. 11-15, 2024

User Guide

This section is to outline the steps needed to setup a Translating Body State Effector in Python using Basilisk.

  1. Import the linearTranslationNDOFStateEffector class:

    from Basilisk.simulation import linearTranslationNDOFStateEffector
    
  2. Create an instantiation of a Translating body:

    translatingBodyEffector = linearTranslationNDOFStateEffector.LinearTranslationNDOFStateEffector()
    
  3. For each degree of freedom, create and set the properties of a translating body. A body may carry zero mass and zero inertia, subject to the condition in the note below:

    translatingBody = linearTranslationNDOFStateEffector.TranslatingBody()
    translatingBody.setMass(50.0)
    translatingBody.setIPntFc_F([[100.0, 0.0, 0.0],
                                 [0.0, 80.0, 0.0],
                                 [0.0, 0.0, 50.0]])
    translatingBody.setDCM_FP([[0.0, -1.0, 0.0],
                               [0.0, 0.0, -1.0],
                               [1.0, 0.0, 0.0]])
    translatingBody.setR_FcF_F([[0.8],
                                [0.5],
                                [-0.3]])
    translatingBody.setR_F0P_P([[0.1],
                                [-0.2],
                                [0.4]])
    translatingBody.setFHat_P([[3.0 / 5.0], [4.0 / 5.0], [0.0]])
    translatingBodyEffector.addTranslatingBody(translatingBody)
    
  4. (Optional) Define initial conditions of the effector. Default values are zero states:

    translatingBody.setRhoInit(1.0)
    translatingBody.setRhoDotInit(0.05)
    
  5. (Optional) Define spring and damper coefficients. Default values are zero:

    translatingBody.setK(100.0)
    translatingBody.setC(0.0)
    

    Note

    Initialization rejects a chain whose joint mass matrix is singular, which happens exactly when some nonzero combination of joint rates leaves every body carrying mass stationary. A massless outermost body and a massless body sharing its axis with the body outboard of it are the simplest cases, but the condition is collective rather than pairwise. Massless stages along \(\hat{x}\) and \(\hat{y}\) followed by a massive stage along \(\hat{x} + \hat{y}\) have pairwise independent axes and are still rejected, because the three axes span only two dimensions.

  6. (Optional) Define a unique name for each state. If you have multiple effectors, 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:

    translatingBodyEffector.setNameOfRhoState("translatingBodyRho")
    translatingBodyEffector.setNameOfRhoDotState("translatingBodyRhoDot")
    
  7. (Optional) Connect a command force message, which carries one force per degree of freedom:

    cmdArray = messaging.ArrayMotorForceMsgPayload()
    cmdArray.motorForce = [cmdForce]  # [N]
    cmdMsg = messaging.ArrayMotorForceMsg().write(cmdArray)
    translatingBodyEffector.motorForceInMsg.subscribeTo(cmdMsg)
    
  8. (Optional) Connect an axis-locking message, which carries one flag per degree of freedom (0 means the axis is free to move and 1 locks the axis):

    lockArray = messaging.ArrayEffectorLockMsgPayload()
    lockArray.effectorLockFlag = [1]
    lockMsg = messaging.ArrayEffectorLockMsg().write(lockArray)
    translatingBodyEffector.motorLockInMsg.subscribeTo(lockMsg)
    
  9. (Optional) Connect a displacement and displacement rate reference message to any degree of freedom:

    translationRef = messaging.LinearTranslationRigidBodyMsgPayload()
    translationRef.rho = 0.2
    translationRef.rhoDot = 0.0
    translationRefMsg = messaging.LinearTranslationRigidBodyMsg().write(translationRef)
    translatingBodyEffector.translatingBodyRefInMsgs[0].subscribeTo(translationRefMsg)
    
  10. The linear states of each body are created using the output message vector translatingBodyOutMsgs.

  11. The translating body config log state output message vector is translatingBodyConfigLogOutMsgs.

  12. Add the effector to your spacecraft:

    scObject.addStateEffector(translatingBodyEffector)
    

    See C++ Module: spacecraft documentation on how to set up a spacecraft object.

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 translating bodies rather than by the hub:

translatingBodyEffector.addDynamicEffector(childEffector, segment)

Here segment is the one-based body number, counting outward from the hub, so 1 is the body attached to the hub. The child then reads that body’s inertial position, velocity, attitude, and angular velocity in place of the hub’s, and any geometry given to the child is expressed in that 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:

scSim.AddModelToTask(taskName, translatingBodyEffector)
scSim.AddModelToTask(taskName, childEffector)

struct TranslatingBody
#include <linearTranslationNDOFStateEffector.h>

translating body structure

Public Functions

void setMass(double mass)

setter for mass property

void setK(double k)

setter for k property

void setC(double c)

setter for c property

inline void setRhoInit(double rhoInit)

setter for rhoInit property

inline void setRhoDotInit(double rhoDotInit)

setter for rhoDotInit property

void setFHat_P(Eigen::Vector3d fHat_P)

setter for fHat_P property

inline void setR_FcF_F(Eigen::Vector3d r_FcF_F)

setter for r_FcF_F property

inline void setR_F0P_P(Eigen::Vector3d r_F0P_P)

setter for r_F0B_B property

inline void setIPntFc_F(Eigen::Matrix3d IPntFc_F)

setter for IPntFc_F property

inline void setDCM_FP(Eigen::Matrix3d dcm_FP)

setter for dcm_FB property

inline double getMass() const

getter for mass property

inline double getK() const

getter for k property

inline double getC() const

getter for c property

inline double getRhoInit() const

getter for rhoInit property

inline double getRhoDotInit() const

getter for rhoDotInit property

inline Eigen::Vector3d getFHat_P() const

getter for fHat_P property

inline Eigen::Vector3d getR_FcF_F() const

getter for r_FcF_F property

inline Eigen::Vector3d getR_F0P_P() const

getter for r_F0P_P property

inline Eigen::Matrix3d getIPntFc_F() const

getter for IPntFc_F property

inline Eigen::Matrix3d getDCM_FP() const

getter for dcm_FP property

Private Functions

template<typename Type>
inline void assignStateParamNames(Type effector)

Assign this body’s state-engine property names to an attached effector.

Template Parameters:

Type – Pointer type for an effector that accepts inertial property names.

Parameters:

effector – Effector that receives the body’s inertial property names.

Private Members

double mass = 0.0

[kg] mass of translating arm

double k = 0.0

[N/m] translational spring constant

double c = 0.0

[N-s/m] translational damping coefficient

double rhoInit = 0.0

[m] initial translating body distance from equilibrium

double rhoDotInit = 0.0

[m/s] initial translating body velocity of F frame wrt F0 frame

double rhoRef = 0.0

[m] reference translating body distance from equilibrium

double rhoDotRef = 0.0

[m/s] reference translating body velocity of F frame wrt F0 frame

double u = 0.0

[N] motor force acting along the translating axis of the body

bool isAxisLocked = false

&#8212; lock flag

Eigen::Matrix3d IPntFc_F = Eigen::Matrix3d::Identity()

[kg-m^2] Inertia of body about point Fc in F frame components

Eigen::Vector3d r_FcF_F = Eigen::Vector3d::Zero()

[m] vector pointing from translating frame F origin to point Fc (center of mass of arm) in F frame components

Eigen::Vector3d r_F0P_P = Eigen::Vector3d::Zero()

[m] vector pointing from parent origin to translating frame F0 origin in parent frame components

Eigen::Vector3d fHat_P = {1.0, 0.0, 0.0}

&#8212; translating axis in parent frame components.

Eigen::Matrix3d dcm_FP = Eigen::Matrix3d::Identity()

&#8212; DCM from parent frame to current F frame

double rho = 0.0

[m] translating body distance from equilibrium

double rhoDot = 0.0

[m/s] translating body velocity of F frame wrt F0 frame

Eigen::Vector3d r_FF0_B = Eigen::Vector3d::Zero()

[m] vector pointing from translating frame F0 to translating frame F (magnitude rho)

Eigen::Vector3d r_F0P_B = Eigen::Vector3d::Zero()

[m] vector pointing from parent translating frame P to translating frame F0

Eigen::Vector3d fHat_B = Eigen::Vector3d::Zero()

&#8212; translating axis in B frame components.

Eigen::Vector3d r_FcF_B = Eigen::Vector3d::Zero()

[m] vector pointing from translating frame F origin to point Fc (center of mass of arm) in B frame components

Eigen::Vector3d r_FB_B = Eigen::Vector3d::Zero()

[m] vector pointing from body frame B origin to F frame in B frame components

Eigen::Vector3d r_FcB_B = Eigen::Vector3d::Zero()

[m] vector pointing from body frame B origin to Fc in B frame components

Eigen::Vector3d r_FP_B = Eigen::Vector3d::Zero()

[m] vector from parent frame to current F frame in B frame components

Eigen::Vector3d rPrime_FB_B = Eigen::Vector3d::Zero()

[m/s] body frame time derivative of r_FB_B

Eigen::Vector3d rPrime_FcF_B = Eigen::Vector3d::Zero()

[m/s] body frame time derivative of r_FcF_B

Eigen::Vector3d rPrime_FcB_B = Eigen::Vector3d::Zero()

[m/s] body frame time derivative of r_FcB_B

Eigen::Vector3d rPrime_FP_B = Eigen::Vector3d::Zero()

[m/s] body frame time derivative of r_FP_B

Eigen::Vector3d rPrime_FF0_B = Eigen::Vector3d::Zero()

[m/s] body frame time derivative of r_FF0_B

Eigen::Vector3d rDot_FcB_B = Eigen::Vector3d::Zero()

[m/s] inertial frame time derivative of r_FcB_B

Eigen::Matrix3d dcm_FB = Eigen::Matrix3d::Identity()

&#8212; DCM from body frame to F frame

Eigen::Matrix3d IPntFc_B = Eigen::Matrix3d::Zero()

[kg-m^2] Inertia of body about point Fc in B frame components

Eigen::Matrix3d IPrimePntFc_B = Eigen::Matrix3d::Zero()

[kg-m^2/s] body frame time derivative of IPntFc_B

Eigen::Matrix3d rTilde_FcB_B = Eigen::Matrix3d::Zero()

[m] tilde matrix of r_FcB_B

Eigen::Vector3d r_FcN_N = Eigen::Vector3d::Zero()

[m] position vector of translating body’s center of mass Fc relative to the inertial frame origin N

Eigen::Vector3d v_FcN_N = Eigen::Vector3d::Zero()

[m/s] inertial velocity vector of Fc relative to inertial frame

Eigen::MatrixXd *r_FN_N = nullptr

[m] position vector of the translating frame F origin relative to the inertial frame origin N

Eigen::MatrixXd *v_FN_N = nullptr

[m/s] inertial velocity vector of F relative to inertial frame

Eigen::MatrixXd *sigma_FN = nullptr

&#8212; MRP attitude of frame F relative to inertial frame

Eigen::MatrixXd *omega_FN_F = nullptr

[rad/s] inertial translating body frame angular velocity vector

std::string nameOfInertialPositionProperty

&#8212; identifier for the inertial position property

std::string nameOfInertialVelocityProperty

&#8212; identifier for the inertial velocity property

std::string nameOfInertialAttitudeProperty

&#8212; identifier for the inertial attitude property

std::string nameOfInertialAngVelocityProperty

&#8212; identifier for the inertial angular velocity property

std::vector<DynamicEffector*> dynEffectors

&#8212; vector of dynamic effectors attached to this body

Eigen::Vector3d extForce_B = Eigen::Vector3d::Zero()

[N] attached effector force on this body in B frame components

Eigen::Vector3d extTorquePntF_B = Eigen::Vector3d::Zero()

[N-m] attached effector torque on this body about F in B frame components

BSKLogger bskLogger

Friends

friend class LinearTranslationNDOFStateEffector
class LinearTranslationNDOFStateEffector : public StateEffector, public SysModel
#include <linearTranslationNDOFStateEffector.h>

translating body state effector class

Public Functions

LinearTranslationNDOFStateEffector()

&#8212; Constructor

This is the constructor, setting variables to default values

~LinearTranslationNDOFStateEffector() override

&#8212; Destructor

This is the destructor, releasing the per body output messages

void addTranslatingBody(const std::shared_ptr<TranslatingBody> newBody)

method for adding a new translating body

This method is used to add a translating body.

std::shared_ptr<TranslatingBody> getTranslatingBody(uint64_t index)

method for getting an indexed translating body

This method is used to get a translating body.

inline void setNameOfRhoState(const std::string &nameOfRhoState)

setter for nameOfRhoState property

inline void setNameOfRhoDotState(const std::string &nameOfRhoDotState)

setter for nameOfRhoDotState property

inline std::string getNameOfRhoState() const

getter for nameOfRhoState property

inline std::string getNameOfRhoDotState() const

getter for nameOfRhoDotState property

Public Members

std::vector<Message<LinearTranslationRigidBodyMsgPayload>*> translatingBodyOutMsgs

vector of state output messages

std::vector<Message<SCStatesMsgPayload>*> translatingBodyConfigLogOutMsgs

vector of translating body state config log messages

std::vector<ReadFunctor<LinearTranslationRigidBodyMsgPayload>> translatingBodyRefInMsgs

(optional) reference state input message

ReadFunctor<ArrayMotorForceMsgPayload> motorForceInMsg

&#8212; (optional) motor force input message name

ReadFunctor<ArrayEffectorLockMsgPayload> motorLockInMsg

&#8212; (optional) motor lock input message name

Private Functions

void Reset(uint64_t CurrentClock) final

This method is used to reset the module.

void readInputMessages()

This method reads motor force, lock flag, and reference state messages.

void writeOutputStateMessages(uint64_t CurrentClock) final

This method takes the computed rho states and outputs them to the messaging system.

void UpdateState(uint64_t CurrentSimNanos) final

This method is used so that the simulation will ask TB to update messages

void registerStates(DynParamManager &statesIn) final

This method allows the TB state effector to register its states: rho and rhoDot with the dynamic parameter manager

void registerProperties(DynParamManager &states) final

This method registers each translating body’s inertial properties with the dynamic parameter manager and links them into dependent dynamic effectors

Parameters:

states – the dynamic parameter manager holding the published properties

void addDynamicEffector(DynamicEffector *newDynamicEffector, int segment) final

This method attaches a dynamicEffector to one of the translating bodies

Parameters:
  • newDynamicEffector – the dynamic effector to be attached

  • segment – the translating body to attach to, counting outward from the hub starting at 1

void linkInStates(DynParamManager &states) final

This method allows the TB state effector to have access to the hub states and gravity

void updateContributions(double integTime, BackSubMatrices &backSubContr, Eigen::MRPd sigma_BN, Eigen::Vector3d omega_BN_B, Eigen::Vector3d g_N) final

This method allows the TB state effector to give its contributions to the matrices needed for the back-sub method

void computeDependentEffectors(BackSubMatrices &backSubContr, double integTime)

This method collects the loads from any attached dynamic effectors and applies them to the hub

Parameters:
  • backSubContr – the Backsubstitution contributions this effector adds to the hub

  • integTime – the integration time the attached effectors evaluate their loads at

void computeMRho(Eigen::MatrixXd &MRho)

This method compute MRho for back-sub

void computeARhoStar(Eigen::MatrixX3d &ARhoStar)

This method compute ARhoStar for back-sub

void computeBRhoStar(Eigen::MatrixX3d &BRhoStar)

This method compute BRhoStar for back-sub

void computeCRhoStar(Eigen::VectorXd &CRhoStar, const Eigen::Vector3d &g_N)

This method compute CRhoStar for back-sub

void computeBackSubContributions(BackSubMatrices &backSubContr) const

This method computes the back-sub contributions of the system

void computeDerivatives(double integTime, Eigen::Vector3d rDDot_BN_N, Eigen::Vector3d omegaDot_BN_B, Eigen::MRPd sigma_BN) final

This method is used to find the derivatives for the TB stateEffector: rhoDDot and the kinematic derivative

void updateEffectorMassProps(double integTime) final

This method allows the TB state effector to provide its contributions to the mass props and mass prop rates of the spacecraft

void updateEnergyMomContributions(double integTime, Eigen::Vector3d &rotAngMomPntCContr_B, double &rotEnergyContr, Eigen::Vector3d omega_BN_B) final

This method is for calculating the contributions of the TB state effector to the energy and momentum of the spacecraft

void prependSpacecraftNameToStates() final

This method prepends the name of the spacecraft for multi-spacecraft simulations.

void validateConfiguration()

This method runs every configuration check. Spacecraft initialization always reaches it through registerStates(), whereas Reset() runs only when the effector is also added to a task

void checkBodyConfiguration()

This method checks each translating body’s user set frame and inertia

void checkJointMassMatrix()

This method checks that the joint mass matrix the equations of motion invert is not singular

void computeTranslatingBodyInertialStates()

This method computes the translating body states relative to the inertial frame

Private Members

int N = 0

&#8212; number of translating body axes defined in the system

std::vector<std::shared_ptr<TranslatingBody>> translatingBodyVec

&#8212; vector of TB effector structs

Eigen::MatrixX3d ARho

&#8212; rDDot_BN term for back substitution

Eigen::MatrixX3d BRho

&#8212; omegaDot_BN term for back substitution

Eigen::VectorXd CRho

&#8212; scalar term for back substitution

Eigen::Vector3d omega_BN_B = Eigen::Vector3d::Zero()

[rad/s] angular velocity of the B frame wrt the N frame in B frame components

Eigen::MRPd sigma_BN = {0.0, 0.0, 0.0}

&#8212; body frame attitude wrt to the N frame in MRPs

Eigen::Matrix3d dcm_BN = Eigen::Matrix3d::Identity()

&#8212; DCM from inertial frame to body frame

Eigen::MatrixXd *inertialPositionProperty = nullptr

[m] r_N inertial position relative to system spice zeroBase/refBase

Eigen::MatrixXd *inertialVelocityProperty = nullptr

[m] v_N inertial velocity relative to system spice zeroBase/refBase

StateData *rhoState = nullptr
StateData *rhoDotState = nullptr
StateData *hubSigmaState = nullptr

hub attitude state, read live for the published kinematics

std::string nameOfRhoState

&#8212; identifier for the rho state data container

std::string nameOfRhoDotState

&#8212; identifier for the rhoDot state data container

std::string propertyNameIndex

&#8212; effector identifier used to name the per body properties

Private Static Attributes

static uint64_t effectorID = 1

[] ID number of this effector