|
| 1 | +Executive Summary |
| 2 | +----------------- |
| 3 | +The faceted spacecraft solar radiation pressure (SRP) module computes the aggregate force and torque acting on the |
| 4 | +spacecraft due to impinging photons from the Sun. The inertial Sun state information must be subscribed |
| 5 | +to the module ``SpicePlanetStateMsgPayload`` input message. The module assumes the spacecraft is modeled as a |
| 6 | +collection of facets, where the facet geometry information is passed as a vector of ``FacetElementBodyMsgPayload`` |
| 7 | +input messages to the module. The facet geometry information is required to be provided in the spacecraft body frame. |
| 8 | +This SRP module does not make any assumptions regarding whether the facets are rigid or articulate. |
| 9 | +The ``facetedSpacecraftModel`` module can be connected upstream and used to transform the facet geometry data from the |
| 10 | +facet frames to the spacecraft body frame. This upstream module can also be used to configure articulating facets. |
| 11 | +Finally, this SRP module also requires the sunlit area of all facets to be pre-computed and connected to the module |
| 12 | +vector of ``ProjectedAreaMsgPayload`` input messages. This information can be passed to the SRP module by connecting |
| 13 | +the facet geometry information to the ``facetedSpacecraftProjectedArea`` module upstream. |
| 14 | + |
| 15 | +.. important:: |
| 16 | + The total number of facets must be set using ``setNumFacets()`` before connecting the facet input message vectors. |
| 17 | + |
| 18 | +.. important:: |
| 19 | + All facet geometry and projected area input message vectors must have lengths equal to ``numFacets``. |
| 20 | + |
| 21 | + |
| 22 | +Message Connection Descriptions |
| 23 | +------------------------------- |
| 24 | +The following table lists all module input messages. |
| 25 | +The module msg connections are set by the user from Python. |
| 26 | +The msg type contains a link to the message structure definition, while the description |
| 27 | +provides information on what each message is used for. |
| 28 | + |
| 29 | +.. list-table:: Module I/O Messages |
| 30 | + :widths: 30 25 45 |
| 31 | + :header-rows: 1 |
| 32 | + |
| 33 | + * - Msg Variable Name |
| 34 | + - Msg Type |
| 35 | + - Description |
| 36 | + * - sunStateInMsg |
| 37 | + - :ref:`SpicePlanetStateMsgPayload` |
| 38 | + - Input message containing the Sun inertial state |
| 39 | + * - facetElementBodyInMsgs |
| 40 | + - :ref:`FacetElementBodyMsgPayload` |
| 41 | + - Input message vector containing facet element data expressed in body-frame components |
| 42 | + * - facetProjectedAreaInMsgs |
| 43 | + - :ref:`ProjectedAreaMsgPayload` |
| 44 | + - Input message vector containing pre-computed per-facet projected areas |
| 45 | + |
| 46 | + |
| 47 | +Module Functions |
| 48 | +---------------- |
| 49 | +Below is a list of functions this simulation module performs: |
| 50 | + |
| 51 | + - Reads the Sun inertial position and computes the Sun direction vector in spacecraft body-frame components |
| 52 | + - Reads facet body-frame geometry and optical coefficients for each facet |
| 53 | + - Reads per-facet projected areas for each facet |
| 54 | + - Computes SRP pressure scaled by spacecraft heliocentric distance |
| 55 | + - Computes and sums per-facet SRP force and torque contributions |
| 56 | + - Writes total SRP force and torque to the dynamic effector base-class outputs ``forceExternal_B`` and ``torqueExternalPntB_B`` |
| 57 | + |
| 58 | + |
| 59 | +Module Assumptions and Limitations |
| 60 | +---------------------------------- |
| 61 | + - The user must call ``setNumFacets()`` before connecting message vectors |
| 62 | + - This module assumes facet normals and center-of-pressure vectors are already expressed in the spacecraft body frame |
| 63 | + - This module expects projected areas to be provided externally; it does not compute projected area internally |
| 64 | + - This module does not read articulation-angle messages directly |
| 65 | + - Facets with non-positive projected area contribute zero SRP force and torque |
| 66 | + |
| 67 | + |
| 68 | +Test Description and Success Criteria |
| 69 | +------------------------------------- |
| 70 | +The unit test for this module is located in :ref:`test_facetedSRPEffector`. The test verifies that the module |
| 71 | +correctly computes the aggregate SRP force and torque acting on the spacecraft due to impinging photons |
| 72 | +from the Sun. The test sets up a simulation with a faceted spacecraft modeled as a cubic hub with two attached |
| 73 | +circular solar arrays. Six square facets represent the cubic hub and four circular facets represent the two solar |
| 74 | +arrays. The test varies the initial state information of both the spacecraft and the Sun. Specifically, the test |
| 75 | +parameterizes: |
| 76 | + |
| 77 | + - Spacecraft initial inertial position |
| 78 | + - Sun inertial position |
| 79 | + - Spacecraft initial attitude |
| 80 | + - Spacecraft initial angular velocity |
| 81 | + |
| 82 | +The test checks that the computed SRP forces and torques at each timestep match the values output from the module. |
| 83 | + |
| 84 | +User Guide |
| 85 | +---------- |
| 86 | +The following steps are required to set up the ``facetedSRPEffector`` module in Python. |
| 87 | + |
| 88 | +.. note:: |
| 89 | + A common setup is to connect ``facetedSpacecraftModel`` upstream to provide body-frame facet geometry and connect |
| 90 | + ``facetedSpacecraftProjectedArea`` upstream to provide per-facet projected areas. |
| 91 | + |
| 92 | +#. Import the required BSK modules:: |
| 93 | + |
| 94 | + from Basilisk.simulation import facetedSRPEffector |
| 95 | + from Basilisk.simulation import facetedSpacecraftProjectedArea |
| 96 | + from Basilisk.simulation import spacecraft |
| 97 | + |
| 98 | +#. Create the spacecraft object and set its initial states:: |
| 99 | + |
| 100 | + sc_object = spacecraft.Spacecraft() |
| 101 | + sc_object.ModelTag = "scObject" |
| 102 | + sc_object.hub.mHub = 750.0 # [kg] |
| 103 | + sc_object.hub.r_BcB_B = [[0.0], [0.0], [1.0]] # [m] |
| 104 | + sc_object.hub.IHubPntBc_B = [[900.0, 0.0, 0.0], [0.0, 800.0, 0.0], [0.0, 0.0, 600.0]] # [kg m^2] |
| 105 | + sc_object.hub.r_CN_NInit = [[-4020338.690396649], [7490566.741852513], [5248299.211589362]] # [m] |
| 106 | + sc_object.hub.v_CN_NInit = [[-5199.77710904224], [-3436.681645356935], [1041.576797498721]] # [m/s] |
| 107 | + sc_object.hub.sigma_BNInit = [0.0, 0.0, 0.0] # [-] |
| 108 | + sc_object.hub.omega_BN_BInit = [0.0, 0.0, 0.0] # [rad/s] |
| 109 | + |
| 110 | +#. Create the SRP module and set the number of facets:: |
| 111 | + |
| 112 | + faceted_srp_effector = facetedSRPEffector.FacetedSRPEffector() |
| 113 | + faceted_srp_effector.ModelTag = "facetedSRPEffector" |
| 114 | + faceted_srp_effector.setNumFacets(2) |
| 115 | + |
| 116 | +#. Create the sun and connect the Sun inertial state message:: |
| 117 | + |
| 118 | + sun_state_message_data = messaging.SpicePlanetStateMsgPayload() |
| 119 | + sun_state_message_data.PositionVector = [0.0, 0.0, 0.0] # [m] |
| 120 | + sun_state_message_data.VelocityVector = [0.0, 0.0, 0.0] # [m/s] |
| 121 | + sun_state_message = messaging.SpicePlanetStateMsg().write(sun_state_message_data) |
| 122 | + |
| 123 | + grav_factory = simIncludeGravBody.gravBodyFactory() |
| 124 | + sun = grav_factory.createSun() |
| 125 | + sun.isCentralBody = True |
| 126 | + grav_factory.gravBodies['sun'].planetBodyInMsg.subscribeTo(sun_state_message) |
| 127 | + faceted_srp_effector.sunStateInMsg.subscribeTo(sun_state_message) |
| 128 | + |
| 129 | +#. Create a :ref:`FacetElementBodyMsgPayload` facet geometry input message for each facet:: |
| 130 | + |
| 131 | + facet_area_list = [0.5, 1.0] # [m^2] |
| 132 | + facet_r_CopB_B_list = [np.array([-0.1, 0.1, -0.1]), |
| 133 | + np.array([0.1, -0.1, -0.1])] # [m] |
| 134 | + facet_nHat_B_list = [np.array([1.0, 0.0, 0.0]), |
| 135 | + np.array([0.0, 1.0, 0.0])] |
| 136 | + facet_rotHat_B_list = [np.array([0.0, 1.0, 0.0]), |
| 137 | + np.array([1.0, 0.0, 0.0])] |
| 138 | + facet_diffuse_coeff_list = [0.1, 0.1] |
| 139 | + facet_specular_coeff_list = [0.9, 0.9] |
| 140 | + |
| 141 | + facet_1_message_data = messaging.FacetElementBodyMsgPayload( |
| 142 | + area = facet_area_list[0], |
| 143 | + r_CopB_B = facet_r_CopB_B_list[0], |
| 144 | + nHat_B = facet_nHat_B_list[0], |
| 145 | + rotHat_B = facet_rotHat_B_list[0], |
| 146 | + c_diffuse = facet_diffuse_coeff_list[0], |
| 147 | + c_specular = facet_specular_coeff_list[0], |
| 148 | + ) |
| 149 | + facet_2_message_data = messaging.FacetElementBodyMsgPayload( |
| 150 | + area = facet_area_list[1], |
| 151 | + r_CopB_B = facet_r_CopB_B_list[1], |
| 152 | + nHat_B = facet_nHat_B_list[1], |
| 153 | + rotHat_B = facet_rotHat_B_list[1], |
| 154 | + c_diffuse = facet_diffuse_coeff_list[1], |
| 155 | + c_specular = facet_specular_coeff_list[1], |
| 156 | + ) |
| 157 | + facet_1_message = messaging.FacetElementBodyMsg().write(facet_1_message_data) |
| 158 | + facet_2_message = messaging.FacetElementBodyMsg().write(facet_2_message_data) |
| 159 | + |
| 160 | +#. Subscribe the facet geometry input messages to the SRP module ``facetElementBodyInMsgs`` input message vector:: |
| 161 | + |
| 162 | + faceted_srp_effector.facetElementBodyInMsgs[0].subscribeTo(facet_1_message) |
| 163 | + faceted_srp_effector.facetElementBodyInMsgs[1].subscribeTo(facet_2_message) |
| 164 | + |
| 165 | +#. Create the faceted spacecraft projected area module and set the total number of facets:: |
| 166 | + |
| 167 | + faceted_sc_projected_area = facetedSpacecraftProjectedArea.FacetedSpacecraftProjectedArea() |
| 168 | + faceted_sc_projected_area.ModelTag = "facetedSpacecraftProjectedArea" |
| 169 | + faceted_sc_projected_area.setNumFacets(2) |
| 170 | + |
| 171 | +#. Subscribe the facet geometry input messages to the projected area module ``facetElementBodyInMsgs`` input message vector:: |
| 172 | + |
| 173 | + faceted_sc_projected_area.facetElementBodyInMsgs[0].subscribeTo(facet_1_message) |
| 174 | + faceted_sc_projected_area.facetElementBodyInMsgs[1].subscribeTo(facet_2_message) |
| 175 | + |
| 176 | +#. Subscribe the projected area module ``facetProjectedAreaOutMsgs`` output message vector to the SRP module ``facetProjectedAreaInMsgs`` input message vector:: |
| 177 | + |
| 178 | + faceted_srp_effector.facetProjectedAreaInMsgs[0].subscribeTo(faceted_sc_projected_area.facetProjectedAreaOutMsgs[0]) |
| 179 | + faceted_srp_effector.facetProjectedAreaInMsgs[1].subscribeTo(faceted_sc_projected_area.facetProjectedAreaOutMsgs[1]) |
| 180 | + |
| 181 | +#. Subscribe other required messages to the projected area module:: |
| 182 | + |
| 183 | + faceted_sc_projected_area.sunStateInMsg.subscribeTo(sun_state_message) |
| 184 | + faceted_sc_projected_area.spacecraftStateInMsg.subscribeTo(sc_object.scStateOutMsg) |
| 185 | + |
| 186 | +#. Add the SRP effector to the spacecraft:: |
| 187 | + |
| 188 | + sc_object.addDynamicEffector(faceted_srp_effector) |
| 189 | + |
| 190 | +#. Add each module to a task:: |
| 191 | + |
| 192 | + test_sim.AddModelToTask(task_name, faceted_sc_projected_area) |
| 193 | + test_sim.AddModelToTask(task_name, sc_object) |
| 194 | + test_sim.AddModelToTask(task_name, faceted_srp_effector) |
| 195 | + |
| 196 | +.. note:: |
| 197 | + Add the spacecraft object to the task after the projected area module to ensure the SRP effector has valid input |
| 198 | + message data at the first integration timestep. |
0 commit comments