Source code for scenarioCustomGravBody

#
#  ISC License
#
#  Copyright (c) 2021, 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"""

.. youtube:: uUomHSGQW3c
   :width: 560
   :height: 315

Overview
--------

Demonstrates how to setup a custom gravity object in Basilisk that is not directly supported by
the ``simIncludeGravBody.py`` file.  In this simulation the sun is created using standard values, the Earth
is created using custom values, and the asteroid Itokawa is created with custom values.

.. image:: /_images/static/scenarioCustomGravObject.jpg
   :align: center

Further, the Vizard binary file is setup to load up a custom CAD model for the asteroid. The spacecraft
orbit is defined relative to the asteroid.  Note, this feature requires :ref:`Vizard <vizard>` version 1.8 or higher.

The script is found in the folder ``basilisk/examples`` and executed by using::

      python3 scenarioCustomGravBody.py

The simulation layout is shown in the following illustration.  A single simulation process is created
which contains both modules.

.. image:: /_images/static/test_scenarioCustomGravBody.svg
   :align: center

:ref:`planetEphemeris` is used to create the planet ephemeris states. The sun is assumed to be stationary,
while Earth is on a circular orbit and Itokawa is on its elliptical heliocentric orbit.

The method ``createCustomGravObject()`` is used to create the BSK grav bodies for both earth and Itokawa.
The earth body is already supported in :ref:`simIncludeGravBody`, but in this script we show how this could
be customized.  The gravity body ephemeris states are connected to the :ref:`planetEphemeris` planet
state output messages.

The ephemeris outputs remain heliocentric because the Sun gravity body is not
connected to an ephemeris message.  Its default zero state therefore represents
the Sun at the heliocentric origin.  Setting ``planetEphemeris.zeroBase`` to
Itokawa would incorrectly place both the Sun and Itokawa at the origin.  To plot
the spacecraft motion relative to the asteroid, the script instead records the
Itokawa state and subtracts it from the spacecraft state during post-processing.

The simulation executes and shows a plot of the spacecraft motion relative to the asteroid.

Illustration of Simulation Results
----------------------------------

::

    show_plots = True

.. image:: /_images/Scenarios/scenarioCustomGravBody1.svg
   :align: center

"""

#
# Basilisk Scenario Script and Integrated Test
#
# Purpose:  Basic simulation showing how to setup a custom gravity object
# Author:   Hanspeter Schaub
# Creation Date:  Feb. 23, 2021
#

import os

import matplotlib.pyplot as plt
from Basilisk.simulation import planetEphemeris
from Basilisk.simulation import spacecraft
from Basilisk.utilities import (SimulationBaseClass, macros, simIncludeGravBody, vizSupport)
from Basilisk.utilities import orbitalMotion
from Basilisk.utilities import simHelpers


# The path to the location of Basilisk
# Used to get the location of supporting data.
fileName = os.path.basename(os.path.splitext(__file__)[0])



[docs] def run(show_plots): """ The scenarios can be run with the followings setups parameters: Args: show_plots (bool): Determines if the script should display plots """ path = os.path.dirname(os.path.abspath(__file__)) # Create simulation variable names simTaskName = "simTask" simProcessName = "simProcess" # Create a sim module as an empty container scSim = SimulationBaseClass.SimBaseClass() # # create the simulation process # dynProcess = scSim.CreateNewProcess(simProcessName) # create the dynamics task and specify the simulation time step information simulationTimeStep = macros.sec2nano(10.0) simulationTime = macros.min2nano(1120.0) dynProcess.addTask(scSim.CreateNewTask(simTaskName, simulationTimeStep)) # setup celestial object ephemeris module gravBodyEphem = planetEphemeris.PlanetEphemeris() gravBodyEphem.ModelTag = 'planetEphemeris' scSim.AddModelToTask(simTaskName, gravBodyEphem) gravBodyEphem.setPlanetNames(planetEphemeris.StringVector(["Itokawa", "earth"])) # specify orbits of gravitational bodies oeAsteroid = planetEphemeris.ClassicElements() oeAsteroid.a = 1.3241 * orbitalMotion.AU * 1000 # meters oeAsteroid.e = 0.2801 oeAsteroid.i = 1.6214*macros.D2R oeAsteroid.Omega = 69.081*macros.D2R oeAsteroid.omega = 162.82*macros.D2R oeAsteroid.f = 90.0*macros.D2R oeEarth = planetEphemeris.ClassicElements() oeEarth.a = orbitalMotion.AU * 1000 # meters oeEarth.e = 0.0167086 oeEarth.i = 7.155 * macros.D2R oeEarth.Omega = 174.9 * macros.D2R oeEarth.omega = 288.1 * macros.D2R oeEarth.f = 270.0 * macros.D2R # specify celestial object orbit gravBodyEphem.planetElements = planetEphemeris.classicElementVector([oeAsteroid, oeEarth]) # Keep these outputs heliocentric. The unlinked Sun gravity body below uses # its default zero state to represent the Sun at the heliocentric origin. # The asteroid state is subtracted from the spacecraft state when plotting. # specify celestial object orientation gravBodyEphem.rightAscension = planetEphemeris.DoubleVector([0.0 * macros.D2R, 0.0 * macros.D2R]) gravBodyEphem.declination = planetEphemeris.DoubleVector([0.0 * macros.D2R, 0.0 * macros.D2R]) gravBodyEphem.lst0 = planetEphemeris.DoubleVector([0.0 * macros.D2R, 0.0 * macros.D2R]) gravBodyEphem.rotRate = planetEphemeris.DoubleVector( [360 * macros.D2R / (12.132 * 3600.), 360 * macros.D2R / (24. * 3600.)]) # setup Sun gravity body gravFactory = simIncludeGravBody.gravBodyFactory() gravFactory.createSun() # setup asteroid gravity body mu = 2.34268 # meters^3/s^2 asteroid = gravFactory.createCustomGravObject("Itokawa", mu, radEquator=200) asteroid.isCentralBody = True # ensure this is the central gravitational body asteroid.planetBodyInMsg.subscribeTo(gravBodyEphem.planetOutMsgs[0]) # setup Earth gravity Body earth = gravFactory.createCustomGravObject("earth", 0.3986004415E+15, radEquator=6378136.6) earth.planetBodyInMsg.subscribeTo(gravBodyEphem.planetOutMsgs[1]) # create SC object scObject = spacecraft.Spacecraft() scObject.ModelTag = "bskSat" gravFactory.addBodiesTo(scObject) scSim.AddModelToTask(simTaskName, scObject) # setup orbit initial conditions about the asteroid oe = orbitalMotion.ClassicElements() oe.a = 500.0 # meters oe.e = 0.0001 oe.i = 33.3 * macros.D2R oe.Omega = 48.2 * macros.D2R oe.omega = 347.8 * macros.D2R oe.f = 85.3 * macros.D2R rN, vN = orbitalMotion.elem2rv(mu, oe) # To set the spacecraft initial conditions, the following initial position and velocity variables are set: scObject.hub.r_CN_NInit = rN # m - r_BN_N scObject.hub.v_CN_NInit = vN # m/s - v_BN_N # # Setup data logging before the simulation is initialized # numDataPoints = 100 samplingTime = simHelpers.samplingTime(simulationTime, simulationTimeStep, numDataPoints) scRec = scObject.scStateOutMsg.recorder(samplingTime) astRec = gravBodyEphem.planetOutMsgs[0].recorder(samplingTime) scSim.AddModelToTask(simTaskName, scRec) scSim.AddModelToTask(simTaskName, astRec) # if this scenario is to interface with the BSK Viz, uncomment the following lines # to save the BSK data to a file, uncomment the saveFile line below # Note that the gravitational body information is pulled automatically from the spacecraft object(s) # Even if custom gravitational bodies are added, this information is pulled by the method below if vizSupport.vizFound: viz = vizSupport.enableUnityVisualization(scSim, simTaskName, scObject # , saveFile=fileName ) viz.settings.showSpacecraftLabels = 1 # load CAD for custom gravity model vizSupport.createCustomModel(viz, # Specifying relative model path is useful for sharing scenarios and resources: modelPath=os.path.join("..", "dataForExamples", "Itokawa", "ItokawaHayabusa.obj"), # Specifying absolute model path is preferable for live-streaming: # modelPath=os.path.join(path, "dataForExamples", "Itokawa", "ItokawaHayabusa.obj"), shader=1, simBodiesToModify=['Itokawa'], scale=[962, 962, 962]) # initialize Simulation scSim.InitializeSimulation() # configure a simulation stop time and execute the simulation run scSim.ConfigureStopTime(simulationTime) scSim.ExecuteSimulation() # retrieve logged spacecraft position relative to asteroid posData = scRec.r_BN_N - astRec.PositionVector # # plot the results # timeAxis = scRec.times() * macros.NANO2HOUR plt.close("all") # clears out plots from earlier test runs plt.figure(1) fig = plt.gcf() ax = fig.gca() ax.ticklabel_format(useOffset=False, style='plain') for idx in range(3): plt.plot(timeAxis, posData[:, idx] , color=simHelpers.getLineColor(idx, 3), label='$r_{BI,' + str(idx) + '}$') plt.legend(loc='lower right') plt.xlabel('Time [h]') plt.ylabel('Itokawa Relative Position [m]') figureList = {} pltName = fileName + "1" figureList[pltName] = plt.figure(1) if show_plots: plt.show() # close the plots being saved off to avoid over-writing old and new figures plt.close("all") return figureList
# # This statement below ensures that the unit test scrip can be run as a # stand-along python script # if __name__ == "__main__": run( True # show_plots )