## ISC License## Copyright (c) 2016, Autonomous Vehicle Systems Lab, University of Colorado at Boulder## Permission to use, copy, modify, and/or distribute this software for any# purpose with or without fee is hereby granted, provided that the above# copyright notice and this permission notice appear in all copies.## THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.#r"""Overview--------This example script demonstrates how to use thrusters to stabilize the tumble of a spacecraft orbiting theEarth, using two separate threads.This script sets up a 6-DOF spacecraft which is orbiting the Earth. The goal is toillustrate how a set of thrusters can be added to the rigid :ref:`spacecraft` hub, and whatFSW modules are needed to control these thrusters. The simulation setup is performed with twoprocesses, similarly to :ref:`scenarioAttitudeFeedback2T`,in which the dynamics and the FSW algorithms are run at different time steps. The control setup is the sameas in :ref:`scenarioAttitudeFeedbackRW`, but here the RW actuation is replaced withthruster based control torque solution.The script is found in the folder ``basilisk/examples`` and executed by using:: python3 scenarioAttitudeFeedback2T_TH.pyThe simulation layout is shown in the following illustration. The two processes (SIM and FSW) are simulatedand run at different time rates. Interface messages are shared across SIM andFSW message passing interfaces (MPIs)... image:: /_images/static/test_scenarioAttitudeFeedback2T_TH.svg :align: centerWhen the simulation completes several plots are shown for the MRP attitude history, the ratetracking errors, the requested torque, the requested forces for each thruster and the On-Time commands.Setup Changes to Simulate Thrusters Dynamic Effectors-----------------------------------------------------At the beginning of the script all the plot functions are declared. Then the fundamental simulation setup is the sameas the one used in :ref:`scenarioAttitudeFeedback2T`.The dynamics simulation is setup using a :ref:`spacecraft` module to which an Earth gravityeffector is attached. The simple navigation module is still used to output the inertial attitude,angular rate, as well as position and velocity messages.The Thruster Dynamic Effector is added to the the rigid spacecraft hub, similarly to:ref:`scenarioAttitudeFeedbackRW`. The support macro ``simIncludeThruster.py``provides several convenient tools to facilitate the setup process. This script allows the user toreadily create thrusters from a database of public specifications, customize them if needed, and addthem to the :ref:`spacecraft` module.The first thing to do is to create the (empty) set of thrusters that will later contain all the devices. Thena fresh instance of the thruster factory class ``thrusterFactory()`` is created. This factory is ableto create a list of thruster devices, and return copies that can easily be manipulated and customized if needed.The next step in this simulation setup is to use ``create()`` to include a particular thruster device.The ``thrusterFactory()`` class contains severalpublic specifications of thruster devices which can be accessed by specifying their name. In our case we will consider``MOOG_Monarc_1`` for the ACS Thrusters configuration, and ``MOOG_Monarc_22_6`` for the DV Thrusters one.The 2nd and 3rd required arguments are respectively the location of thethruster :math:`\hat{\mathbf r}` and the direction of its force :math:`\hat{\mathbf g}_t`. Bothvectors are expressed in the :math:`\cal B`-frame. The remaining arguments are all optional.The thrusters are generated by using the ``create()`` command inside a 'for' loop, which has thejob of assigning the respective location and direction arguments to each thruster, by cycling through the twopre-defined arrays '`location`' and '`direction`'.The following table provides a comprehensive list of all the optional arguments of the ``create()``command. This table list the arguments, default values, as well as expected units.+---------------------+-------+----------+----------------------------------------+--------------------+| Argument | Units | Type | Description | Default |+=====================+=======+==========+========================================+====================+| useMinPulseTime | | Bool | flag if the thruster model should | False || | | | use a minimum impulse time | |+---------------------+-------+----------+----------------------------------------+--------------------+| areaNozzle | m^2 | Float | thruster nozzle exhaust cone exit area | 0.1 |+---------------------+-------+----------+----------------------------------------+--------------------+| steadyIsp | s | Float | thruster fuel efficiency in Isp | 100.0 |+---------------------+-------+----------+----------------------------------------+--------------------+| MaxThrust | N | Float | maximum thruster force | 0.200 |+---------------------+-------+----------+----------------------------------------+--------------------+| thrusterMagDisp | % | Float | thruster dispersion percentage | 0.0 |+---------------------+-------+----------+----------------------------------------+--------------------+| MinOnTime | s | Float | thruster minimum on time | 0.020 |+---------------------+-------+----------+----------------------------------------+--------------------+The command ``addToSpacecraft()`` adds all the created thrusters to the :ref:`spacecraft` module. The final stepis to add the :ref:`thrusterDynamicEffector` to the list of simulation tasks.Flight Algorithm Changes to Control Thrusters---------------------------------------------The general flight algorithm setup is the same as in the earlier simulation scripts. Here weuse again the :ref:`inertial3D` guidance module, the :ref:`attTrackingError` module to evaluate thetracking error states, and the :ref:`mrpFeedback` module to provide the desired :math:`{\mathbf L}_r`control torque vector. In addition, this time, we have to add two more modules: :ref:`thrForceMapping`and :ref:`thrFiringSchmitt`.The :ref:`thrForceMapping` module takes a commanded attitude control torque vector and determines a set of desiredthruster force values to implement this torque. It is assumed that the nominal thruster configuration is such thatpure torque solutions are possible. The module supports both on- and off-pulsing solutions, includingcases where the thruster solutions are saturated due to a large commanded attitude control torque.The module set up is done in an analogous way as the previous ones. It can be noted that one of the inputscorresponds to the output of the :ref:`mrpFeedback`, being the commanded control torque. The other ones are theinformation on the thrusters configuration and spacecraft inertia, whose messages will be created later in the script.In addition, the control axes are specified using the full identity matrix for ACS thrusters, and its firsttwo rows for the DV ones, since in the latter case we are not able to control one axis (z in our case),due to the geometrical configuration. The last value to specify is the ``thrForceSign``, which will have thevalue of -1 if off-pulsing DV thrusters are employed, and +1 with the on-pulsing ACS configuration.The last needed FSW module is :ref:`thrFiringSchmitt`. A Schmitt trigger logic is implemented to map a desiredthruster force value into a thruster on command time. The module reads in the attitude control thrusterforce values for both on- and off-pulsing scenarios, and then maps this into a time which specifies howlong a thruster should be on. Four values are specified: ``thrMinFireTime`` (minimum thruster on-time in seconds),``level_on`` (Upper duty cycle percentage threshold relative to t min to turn on thrusters), ``level_off``(upper duty cycle percentage threshold relative to t min to turn on thrusters), and ``baseThrustState`` (0 by defaultand set to 1 for DV thrusters). As expected, the thrusters forceinput is directly the output of ``thrForceMapping``, and also in this case we will need the thrusters configurationmessage. It can be noted how the output of this module ends up to be the input commands for the:ref:`thrusterDynamicEffector`.The flight algorithm needs to know how many thruster devices are on the spacecraft and what theirlocation and direction are. This is set through a flight software message that is readin by flight algorithm modules that need this info. To write the required flight thrusters configuration messagea separate support macros called ``fswSetupThrusters.py`` is used.Illustration of Simulation Results----------------------------------:: show_plots = True, useDVThrusters = FalseThe first scenariohas the 8 ACS Thrusters. By looking at the plots we can see how every axis is controlled, andthe de-tumbling action is perfectly performed.We can also see how the requested force for each thruster (third plot) never reaches the 1 N limit (apart from duringthe initial transitory), which means that they are never saturated... image:: /_images/Scenarios/scenarioAttitudeFeedback2T_TH10.svg :align: center.. image:: /_images/Scenarios/scenarioAttitudeFeedback2T_TH20.svg :align: center.. image:: /_images/Scenarios/scenarioAttitudeFeedback2T_TH30.svg :align: center.. image:: /_images/Scenarios/scenarioAttitudeFeedback2T_TH40.svg :align: center.. image:: /_images/Scenarios/scenarioAttitudeFeedback2T_TH50.svg :align: center:: show_plots = True, useDVThrusters = TrueIn this setup we use the 6 DV Thrusters configuration. In this case, given the spacial configuration of the thrusters,it is impossible to control the third axis, so the result is a spacecraft attitude in which the x, y axes arecontrolled, but with a tumbling motion in the z axis. In this setup it can be clearly seenhow the control action is performed just on the x and y axes, leaving thespacecraft tumbling around the z one. Another important remark is that, since the default state of the DV thrustersis 'on', the requested thruster force is always negative, as it can be seen in the plot... image:: /_images/Scenarios/scenarioAttitudeFeedback2T_TH11.svg :align: center.. image:: /_images/Scenarios/scenarioAttitudeFeedback2T_TH21.svg :align: center.. image:: /_images/Scenarios/scenarioAttitudeFeedback2T_TH31.svg :align: center.. image:: /_images/Scenarios/scenarioAttitudeFeedback2T_TH41.svg :align: center.. image:: /_images/Scenarios/scenarioAttitudeFeedback2T_TH51.svg :align: center"""## Basilisk Scenario Script and Integrated Test## Purpose: Integrated test of the spacecraft(), extForceTorque, simpleNav(), thrusterDynamicEffector() and# mrpFeedback() modules. Illustrates a 6-DOV spacecraft detumbling in orbit, while using thrusters# to do the attitude control actuation.# Author: Giulio Napolitano# Creation Date: June 26, 2019#importosimportmatplotlib.pyplotaspltimportnumpyasnp# The path to the location of Basilisk# Used to get the location of supporting data.fromBasiliskimport__path__# import message declarationsfromBasilisk.architectureimportmessagingfromBasilisk.fswAlgorithmsimportattTrackingErrorfromBasilisk.fswAlgorithmsimportinertial3D# import FSW Algorithm related supportfromBasilisk.fswAlgorithmsimportmrpFeedbackfromBasilisk.fswAlgorithmsimportthrFiringSchmittfromBasilisk.fswAlgorithmsimportthrForceMappingfromBasilisk.simulationimportextForceTorquefromBasilisk.simulationimportsimpleNav# import simulation related supportfromBasilisk.simulationimportspacecraftfromBasilisk.simulationimportthrusterDynamicEffector# import general simulation support filesfromBasilisk.utilitiesimportSimulationBaseClassfromBasilisk.utilitiesimportfswSetupThrustersfromBasilisk.utilitiesimportmacrosfromBasilisk.utilitiesimportorbitalMotionfromBasilisk.utilitiesimportsimIncludeGravBodyfromBasilisk.utilitiesimportsimIncludeThrusterfromBasilisk.utilitiesimportunitTestSupport# general support file with common unit test functions# attempt to import vizardfromBasilisk.utilitiesimportvizSupportbskPath=__path__[0]fileName=os.path.basename(os.path.splitext(__file__)[0])# Plotting functions
[docs]defplot_attitude_error(timeDataFSW,dataSigmaBR):"""Plot the attitude errors."""plt.figure(1)foridxinrange(3):plt.plot(timeDataFSW,dataSigmaBR[:,idx],color=unitTestSupport.getLineColor(idx,3),label=r'$\sigma_'+str(idx)+'$')plt.legend(loc='lower right')plt.xlabel('Time [min]')plt.ylabel(r'Attitude Error $\sigma_{B/R}$')
[docs]defplot_rate_error(timeDataFSW,dataOmegaBR):"""Plot the body angular velocity tracking errors."""plt.figure(2)foridxinrange(3):plt.plot(timeDataFSW,dataOmegaBR[:,idx],color=unitTestSupport.getLineColor(idx,3),label=r'$\omega_{BR,'+str(idx)+'}$')plt.legend(loc='lower right')plt.xlabel('Time [min]')plt.ylabel('Rate Tracking Error [rad/s] ')
[docs]defplot_requested_torque(timeDataFSW,dataLr):"""Plot the commanded attitude control torque."""plt.figure(3)foridxinrange(3):plt.plot(timeDataFSW,dataLr[:,idx],color=unitTestSupport.getLineColor(idx,3),label=r'$L_{r,'+str(idx)+r'}$')plt.legend(loc='lower right')plt.xlabel('Time [min]')plt.ylabel(r'Control Torque $L_r$ [Nm]')
[docs]defplot_thrForce(timeDataFSW,dataMap,numTh):"""Plot the Thruster force values."""plt.figure(4)foridxinrange(numTh):plt.plot(timeDataFSW,dataMap[:,idx],color=unitTestSupport.getLineColor(idx,numTh),label=r'$thrForce_{'+str(idx)+r'}$')plt.legend(loc='lower right')plt.xlabel('Time [min]')plt.ylabel('Force requested [N]')
[docs]defplot_OnTimeRequest(timeDataFSW,dataSchm,numTh):"""Plot the thruster on time requests."""plt.figure(5)foridxinrange(numTh):plt.plot(timeDataFSW,dataSchm[:,idx],color=unitTestSupport.getLineColor(idx,numTh),label=r'$OnTimeRequest_{'+str(idx)+r'}$')plt.legend(loc='lower right')plt.xlabel('Time [min]')plt.ylabel('OnTimeRequest [sec]')
[docs]defrun(show_plots,useDVThrusters):""" The scenarios can be run with the followings setups parameters: Args: show_plots (bool): Determines if the script should display plots useDVThrusters (bool): Use 6 DV thrusters instead of the default 8 ACS thrusters. """# Create simulation variable namesdynTaskName="dynTask"dynProcessName="dynProcess"fswTaskName="fswTask"fswProcessName="fswProcess"# Create a sim module as an empty containerscSim=SimulationBaseClass.SimBaseClass()# set the simulation time variable used later onsimulationTime=macros.min2nano(10.)## create the simulation process#dynProcess=scSim.CreateNewProcess(dynProcessName)fswProcess=scSim.CreateNewProcess(fswProcessName)# create the dynamics task and specify the integration update timesimTimeStep=macros.sec2nano(0.1)dynProcess.addTask(scSim.CreateNewTask(dynTaskName,simTimeStep))fswTimeStep=macros.sec2nano(0.5)fswProcess.addTask(scSim.CreateNewTask(fswTaskName,fswTimeStep))## setup the simulation tasks/objects## initialize spacecraft object and set propertiesscObject=spacecraft.Spacecraft()scObject.ModelTag="bsk-Sat"# define the simulation inertiaI=[900.,0.,0.,0.,800.,0.,0.,0.,600.]scObject.hub.mHub=750.0# kg - spacecraft massscObject.hub.r_BcB_B=[[0.0],[0.0],[0.0]]# m - position vector of body-fixed point B relative to CMscObject.hub.IHubPntBc_B=unitTestSupport.np2EigenMatrix3d(I)# add spacecraft object to the simulation processscSim.AddModelToTask(dynTaskName,scObject)# clear prior gravitational body and SPICE setup definitionsgravFactory=simIncludeGravBody.gravBodyFactory()# setup Earth Gravity Bodyearth=gravFactory.createEarth()earth.isCentralBody=True# ensure this is the central gravitational bodymu=earth.mu# attach gravity model to spacecraftgravFactory.addBodiesTo(scObject)# setup extForceTorque module# the control torque is read in through the messaging systemextFTObject=extForceTorque.ExtForceTorque()extFTObject.ModelTag="externalDisturbance"extFTObject.extTorquePntB_B=[[0.25],[-0.25],[0.1]]scObject.addDynamicEffector(extFTObject)scSim.AddModelToTask(dynTaskName,extFTObject)# add the simple Navigation sensor module. This sets the SC attitude, rate, position# velocity navigation messagesNavObject=simpleNav.SimpleNav()sNavObject.ModelTag="SimpleNavigation"scSim.AddModelToTask(dynTaskName,sNavObject)# create arrays for thrusters' locations and directionsifuseDVThrusters:location=[[0,0.95,-1.1],[0.8227241335952166,0.4750000000000003,-1.1],[0.8227241335952168,-0.47499999999999976,-1.1],[0,-0.95,-1.1],[-0.8227241335952165,-0.4750000000000004,-1.1],[-0.822724133595217,0.4749999999999993,-1.1]]direction=[[0.0,0.0,1.0],[0.0,0.0,1.0],[0.0,0.0,1.0],[0.0,0.0,1.0],[0.0,0.0,1.0],[0.0,0.0,1.0]]else:location=[[3.874945160902288e-2,-1.206182747348013,0.85245],[3.874945160902288e-2,-1.206182747348013,-0.85245],[-3.8749451609022656e-2,-1.206182747348013,0.85245],[-3.8749451609022656e-2,-1.206182747348013,-0.85245],[-3.874945160902288e-2,1.206182747348013,0.85245],[-3.874945160902288e-2,1.206182747348013,-0.85245],[3.8749451609022656e-2,1.206182747348013,0.85245],[3.8749451609022656e-2,1.206182747348013,-0.85245]]direction=[[-0.7071067811865476,0.7071067811865475,0.0],[-0.7071067811865476,0.7071067811865475,0.0],[0.7071067811865475,0.7071067811865476,0.0],[0.7071067811865475,0.7071067811865476,0.0],[0.7071067811865476,-0.7071067811865475,0.0],[0.7071067811865476,-0.7071067811865475,0.0],[-0.7071067811865475,-0.7071067811865476,0.0],[-0.7071067811865475,-0.7071067811865476,0.0]]# create the set of thruster in the dynamics taskthrusterSet=thrusterDynamicEffector.ThrusterDynamicEffector()scSim.AddModelToTask(dynTaskName,thrusterSet)# Make a fresh thruster factory instance, this is critical to run multiple timesthFactory=simIncludeThruster.thrusterFactory()# create the thruster devices by specifying the thruster type and its location and directionforpos_B,dir_Binzip(location,direction):ifuseDVThrusters:thFactory.create('MOOG_Monarc_22_6',pos_B,dir_B)else:thFactory.create('MOOG_Monarc_1',pos_B,dir_B)# get number of thruster devicesnumTh=thFactory.getNumOfDevices()# create thruster object container and tie to spacecraft objectthrModelTag="ACSThrusterDynamics"thFactory.addToSpacecraft(thrModelTag,thrusterSet,scObject)## setup the FSW algorithm tasks## setup inertial3D guidance moduleinertial3DObj=inertial3D.inertial3D()inertial3DObj.ModelTag="inertial3D"inertial3DObj.sigma_R0N=[0.,0.,0.]# set the desired inertial orientationscSim.AddModelToTask(fswTaskName,inertial3DObj)# setup the attitude tracking error evaluation moduleattError=attTrackingError.attTrackingError()attError.ModelTag="attErrorInertial3D"scSim.AddModelToTask(fswTaskName,attError)# setup the MRP Feedback control modulemrpControl=mrpFeedback.mrpFeedback()mrpControl.ModelTag="mrpFeedback"scSim.AddModelToTask(fswTaskName,mrpControl)mrpControl.K=3.5*10.0mrpControl.Ki=0.0002# make value negative to turn off integral feedbackmrpControl.P=30.0*10.0mrpControl.integralLimit=2./mrpControl.Ki*0.1# setup the thruster force mapping modulethrForceMappingObj=thrForceMapping.thrForceMapping()thrForceMappingObj.ModelTag="thrForceMapping"scSim.AddModelToTask(fswTaskName,thrForceMappingObj)ifuseDVThrusters:controlAxes_B=[1,0,0,0,1,0]thrForceMappingObj.thrForceSign=-1else:controlAxes_B=[1,0,0,0,1,0,0,0,1]thrForceMappingObj.thrForceSign=+1thrForceMappingObj.controlAxes_B=controlAxes_B# setup the Schmitt trigger thruster firing logic modulethrFiringSchmittObj=thrFiringSchmitt.thrFiringSchmitt()thrFiringSchmittObj.ModelTag="thrFiringSchmitt"scSim.AddModelToTask(fswTaskName,thrFiringSchmittObj)thrFiringSchmittObj.thrMinFireTime=0.002thrFiringSchmittObj.level_on=.75thrFiringSchmittObj.level_off=.25ifuseDVThrusters:thrFiringSchmittObj.baseThrustState=1## Setup data logging before the simulation is initialized#numDataPoints=100samplingTime=unitTestSupport.samplingTime(simulationTime,fswTimeStep,numDataPoints)mrpTorqueLog=mrpControl.cmdTorqueOutMsg.recorder(samplingTime)attErrorLog=attError.attGuidOutMsg.recorder(samplingTime)snTransLog=sNavObject.transOutMsg.recorder(samplingTime)snAttLog=sNavObject.attOutMsg.recorder(samplingTime)thrMapLog=thrForceMappingObj.thrForceCmdOutMsg.recorder(samplingTime)thrTrigLog=thrFiringSchmittObj.onTimeOutMsg.recorder(samplingTime)scSim.AddModelToTask(fswTaskName,mrpTorqueLog)scSim.AddModelToTask(fswTaskName,attErrorLog)scSim.AddModelToTask(fswTaskName,snTransLog)scSim.AddModelToTask(fswTaskName,snAttLog)scSim.AddModelToTask(fswTaskName,thrMapLog)scSim.AddModelToTask(fswTaskName,thrTrigLog)## create FSW simulation messages## create the FSW vehicle configuration messagevehicleConfigOut=messaging.VehicleConfigMsgPayload()vehicleConfigOut.ISCPntB_B=I# use the same inertia in the FSW algorithm as in the simulationvcMsg=messaging.VehicleConfigMsg().write(vehicleConfigOut)# create the FSW Thruster configuration messageifuseDVThrusters:maxThrust=22else:maxThrust=1# A `clearSetup()` should be called first to clear out any pre-existing devices from an# earlier simulation run. Next, the `maxThrust` value should be specified and used in the macro `create()`,# together with the locations and directions, and looped through a for cycle to consider all the thrusters.# The support macro `writeConfigMessage()` creates the required thrusters flight configuration message.fswSetupThrusters.clearSetup()forpos_B,dir_Binzip(location,direction):fswSetupThrusters.create(pos_B,dir_B,maxThrust)fswThrConfigMsg=fswSetupThrusters.writeConfigMessage()# an alternate method to pull un-modifed SIM Thruster configuration and create the corresponding FSW# configuration message is:fswThrConfigMsg=thFactory.getConfigMessage()# set initial Spacecraft States## setup the orbit using classical orbit elementsoe=orbitalMotion.ClassicElements()oe.a=10000000.0# metersoe.e=0.01oe.i=33.3*macros.D2Roe.Omega=48.2*macros.D2Roe.omega=347.8*macros.D2Roe.f=85.3*macros.D2RrN,vN=orbitalMotion.elem2rv(mu,oe)scObject.hub.r_CN_NInit=rN# m - r_CN_NscObject.hub.v_CN_NInit=vN# m/s - v_CN_NscObject.hub.sigma_BNInit=[[0.1],[0.2],[-0.3]]# sigma_BN_BscObject.hub.omega_BN_BInit=[[0.001],[-0.01],[0.03]]# rad/s - omega_BN_B# connect messagessNavObject.scStateInMsg.subscribeTo(scObject.scStateOutMsg)attError.attNavInMsg.subscribeTo(sNavObject.attOutMsg)attError.attRefInMsg.subscribeTo(inertial3DObj.attRefOutMsg)mrpControl.guidInMsg.subscribeTo(attError.attGuidOutMsg)mrpControl.vehConfigInMsg.subscribeTo(vcMsg)thrForceMappingObj.cmdTorqueInMsg.subscribeTo(mrpControl.cmdTorqueOutMsg)thrForceMappingObj.thrConfigInMsg.subscribeTo(fswThrConfigMsg)thrForceMappingObj.vehConfigInMsg.subscribeTo(vcMsg)thrFiringSchmittObj.thrConfInMsg.subscribeTo(fswThrConfigMsg)thrFiringSchmittObj.thrForceInMsg.subscribeTo(thrForceMappingObj.thrForceCmdOutMsg)thrusterSet.cmdsInMsg.subscribeTo(thrFiringSchmittObj.onTimeOutMsg)# if this scenario is to interface with the BSK Viz, uncomment the following linesviz=vizSupport.enableUnityVisualization(scSim,dynTaskName,scObject# , saveFile=fileName,thrEffectorList=thrusterSet,thrColors=vizSupport.toRGBA255("red"))vizSupport.setActuatorGuiSetting(viz,showThrusterLabels=True)## initialize Simulation#scSim.InitializeSimulation()## configure a simulation stop time and execute the simulation run#scSim.ConfigureStopTime(simulationTime)scSim.ExecuteSimulation()## retrieve the logged data#dataLr=mrpTorqueLog.torqueRequestBodydataSigmaBR=attErrorLog.sigma_BRdataOmegaBR=attErrorLog.omega_BR_BdataMap=thrMapLog.thrForcedataSchm=thrTrigLog.OnTimeRequestnp.set_printoptions(precision=16)## plot the results#timeDataFSW=attErrorLog.times()*macros.NANO2MINplt.close("all")# clears out plots from earlier test runsplot_requested_torque(timeDataFSW,dataLr)figureList={}pltName=fileName+"1"+str(int(useDVThrusters))figureList[pltName]=plt.figure(1)plot_rate_error(timeDataFSW,dataOmegaBR)pltName=fileName+"2"+str(int(useDVThrusters))figureList[pltName]=plt.figure(2)plot_attitude_error(timeDataFSW,dataSigmaBR)pltName=fileName+"3"+str(int(useDVThrusters))figureList[pltName]=plt.figure(3)plot_thrForce(timeDataFSW,dataMap,numTh)pltName=fileName+"4"+str(int(useDVThrusters))figureList[pltName]=plt.figure(4)plot_OnTimeRequest(timeDataFSW,dataSchm,numTh)pltName=fileName+"5"+str(int(useDVThrusters))figureList[pltName]=plt.figure(5)ifshow_plots:plt.show()# close the plots being saved off to avoid over-writing old and new figuresplt.close("all")returnfigureList
## This statement below ensures that the unit test scrip can be run as a# stand-along python script#if__name__=="__main__":run(True,# show_plotsFalse,# useDVThrusters)