#
# ISC License
#
# Copyright (c) 2021, Autonomous Vehicle Systems Lab, University of Colorado 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.
#
#
import numpy as np
from Basilisk.architecture import messaging
from Basilisk.fswAlgorithms import smallBodyWaypointFeedback
from Basilisk.simulation import planetEphemeris
from Basilisk.utilities import SimulationBaseClass
from Basilisk.utilities import macros
from Basilisk.utilities import orbitalMotion
from Basilisk.utilities import unitTestSupport
# @pytest.mark.parametrize("accuracy", [1e-12])
# @pytest.mark.parametrize("param1, param2", [
# (1, 1)
# ,(1, 3)
# ])
[docs]
def test_smallBodyWaypointFeedback(show_plots):
r"""
**Validation Test Description**
This test checks two things: a large force output when the spacecraft is far from the waypoint, and a small force
output when the spacecraft is at the waypoint.
**Test Parameters**
Args:
:param show_plots: flag if plots should be shown.
**Description of Variables Being Tested**
In this test, the ``forceRequestBody`` variable in the :ref:`CmdForceBodyMsgPayload` output by the module is tested.
When far away from the waypoint, the force request should be larger than 1 N. When close to the waypoint, the force
request should only account for third body perturbations and SRP.
"""
[testResults1, testMessages1] = smallBodyWaypointFeedbackTestFunction1()
[testResults2, testMessages2] = smallBodyWaypointFeedbackTestFunction2()
assert (testResults1 + testResults2) < 1, [testMessages1, testMessages2]
[docs]
def smallBodyWaypointFeedbackTestFunction1():
"""This test checks for a large force return when far away from the waypoint"""
testFailCount = 0
testMessages = []
unitTaskName = "unitTask"
unitProcessName = "TestProcess"
unitTestSim = SimulationBaseClass.SimBaseClass()
testProcessRate = macros.sec2nano(0.5)
testProc = unitTestSim.CreateNewProcess(unitProcessName)
testProc.addTask(unitTestSim.CreateNewTask(unitTaskName, testProcessRate))
# setup module to be tested
module = smallBodyWaypointFeedback.SmallBodyWaypointFeedback()
module.ModelTag = "smallBodyWaypointFeedback1"
unitTestSim.AddModelToTask(unitTaskName, module)
module.A_sc = 1. # Surface area of the spacecraft, m^2
module.M_sc = 300 # Mass of the spacecraft, kg
module.IHubPntC_B = unitTestSupport.np2EigenMatrix3d([82.12, 0.0, 0.0, 0.0, 98.40, 0.0, 0.0, 0.0, 121.0]) # sc inertia
module.mu_ast = 4.892 # Gravitational constant of the asteroid
module.x1_ref = [-2000., 0., 0.]
module.x2_ref = [0.0, 0.0, 0.0]
module.K1 = unitTestSupport.np2EigenMatrix3d([5e-4, 0e-5, 0e-5, 0e-5, 5e-4, 0e-5, 0e-5, 0e-5, 5e-4])
module.K2 = unitTestSupport.np2EigenMatrix3d([1., 0., 0., 0., 1., 0., 0., 0., 1.])
# Set the orbital parameters of the asteroid
oeAsteroid = planetEphemeris.ClassicElementsMsgPayload()
oeAsteroid.a = 1.1259 * orbitalMotion.AU * 1000 # meters
oeAsteroid.e = 0.20373
oeAsteroid.i = 6.0343 * macros.D2R
oeAsteroid.Omega = 2.01820 * macros.D2R
oeAsteroid.omega = 66.304 * macros.D2R
oeAsteroid.f = 346.32 * macros.D2R
r_ON_N, v_ON_N = orbitalMotion.elem2rv(orbitalMotion.MU_SUN*(1000.**3), oeAsteroid)
# Create the position and velocity of states of the s/c wrt the small body hill frame origin
r_BO_N = np.array([-2000., 1500., 1000.]) # Position of the spacecraft relative to the body
v_BO_N = np.array([0., 0., 0.]) # Velocity of the spacecraft relative to the body
# Create the inertial position and velocity of the s/c
r_BN_N = np.add(r_BO_N, r_ON_N)
v_BN_N = np.add(v_BO_N, v_ON_N)
# Configure blank module input messages
asteroidEphemerisInMsgData = messaging.EphemerisMsgPayload()
asteroidEphemerisInMsgData.r_BdyZero_N = r_ON_N
asteroidEphemerisInMsgData.v_BdyZero_N = v_ON_N
asteroidEphemerisInMsg = messaging.EphemerisMsg().write(asteroidEphemerisInMsgData)
navTransInMsgData = messaging.NavTransMsgPayload()
navTransInMsgData.r_BN_N = r_BN_N
navTransInMsgData.v_BN_N = v_BN_N
navTransInMsg = messaging.NavTransMsg().write(navTransInMsgData)
navAttInMsgData = messaging.NavAttMsgPayload()
navAttInMsgData.sigma_BN = np.array([0.1, 0.0, 0.0])
navAttInMsg = messaging.NavAttMsg().write(navAttInMsgData)
sunEphemerisInMsgData = messaging.EphemerisMsgPayload()
sunEphemerisInMsg = messaging.EphemerisMsg().write(sunEphemerisInMsgData)
# subscribe input messages to module
module.navTransInMsg.subscribeTo(navTransInMsg)
module.navAttInMsg.subscribeTo(navAttInMsg)
module.asteroidEphemerisInMsg.subscribeTo(asteroidEphemerisInMsg)
module.sunEphemerisInMsg.subscribeTo(sunEphemerisInMsg)
# setup output message recorder objects
forceOutMsgRec = module.forceOutMsg.recorder()
unitTestSim.AddModelToTask(unitTaskName, forceOutMsgRec)
unitTestSim.InitializeSimulation()
unitTestSim.ConfigureStopTime(macros.sec2nano(0.))
unitTestSim.ExecuteSimulation()
if np.linalg.norm(forceOutMsgRec.forceRequestBody) <= 1:
testFailCount += 1
testMessages.append("FAILED: " + module.ModelTag + " Module failed "
+ "force output" + " unit test")
if testFailCount == 0:
print("PASSED: " + module.ModelTag)
else:
print(testMessages)
return [testFailCount, "".join(testMessages)]
[docs]
def smallBodyWaypointFeedbackTestFunction2():
"""This test checks that the force output is near zero when at the waypoint"""
testFailCount = 0
testMessages = []
unitTaskName = "unitTask"
unitProcessName = "TestProcess"
unitTestSim = SimulationBaseClass.SimBaseClass()
testProcessRate = macros.sec2nano(0.5)
testProc = unitTestSim.CreateNewProcess(unitProcessName)
testProc.addTask(unitTestSim.CreateNewTask(unitTaskName, testProcessRate))
# setup module to be tested
module = smallBodyWaypointFeedback.SmallBodyWaypointFeedback()
module.ModelTag = "smallBodyWaypointFeedback2"
unitTestSim.AddModelToTask(unitTaskName, module)
module.A_sc = 1. # Surface area of the spacecraft, m^2
module.M_sc = 300 # Mass of the spacecraft, kg
module.IHubPntC_B = unitTestSupport.np2EigenMatrix3d([82.12, 0.0, 0.0, 0.0, 98.40, 0.0, 0.0, 0.0, 121.0]) # sc inertia
module.mu_ast = 4.892 # Gravitational constant of the asteroid
module.x1_ref = [-2000., 0., 0.]
module.x2_ref = [0.0, 0.0, 0.0]
module.K1 = unitTestSupport.np2EigenMatrix3d([5e-4, 0e-5, 0e-5, 0e-5, 5e-4, 0e-5, 0e-5, 0e-5, 5e-4])
module.K2 = unitTestSupport.np2EigenMatrix3d([1., 0., 0., 0., 1., 0., 0., 0., 1.])
# Set the orbital parameters of the asteroid
oeAsteroid = planetEphemeris.ClassicElementsMsgPayload()
oeAsteroid.a = 1.1259 * orbitalMotion.AU * 1000 # meters
oeAsteroid.e = 0.20373
oeAsteroid.i = 6.0343 * macros.D2R
oeAsteroid.Omega = 2.01820 * macros.D2R
oeAsteroid.omega = 66.304 * macros.D2R
oeAsteroid.f = 346.32 * macros.D2R
r_ON_N, v_ON_N = orbitalMotion.elem2rv(orbitalMotion.MU_SUN*(1000.**3), oeAsteroid)
# Create the position and velocity of states of the s/c wrt the small body hill frame
r_BO_H = np.array([-2000., 0., 0.]) # Position of the spacecraft relative to the body
v_BO_H = np.array([0., 0., 0.]) # Velocity of the spacecraft relative to the body
r_BN_N, v_BN_N = orbitalMotion.hill2rv(r_ON_N, v_ON_N, r_BO_H, v_BO_H)
# Configure blank module input messages
asteroidEphemerisInMsgData = messaging.EphemerisMsgPayload()
asteroidEphemerisInMsgData.r_BdyZero_N = r_ON_N
asteroidEphemerisInMsgData.v_BdyZero_N = v_ON_N
asteroidEphemerisInMsg = messaging.EphemerisMsg().write(asteroidEphemerisInMsgData)
navTransInMsgData = messaging.NavTransMsgPayload()
navTransInMsgData.r_BN_N = r_BN_N
navTransInMsgData.v_BN_N = v_BN_N
navTransInMsg = messaging.NavTransMsg().write(navTransInMsgData)
navAttInMsgData = messaging.NavAttMsgPayload()
navAttInMsgData.sigma_BN = np.array([0.1, 0.0, 0.0])
navAttInMsg = messaging.NavAttMsg().write(navAttInMsgData)
sunEphemerisInMsgData = messaging.EphemerisMsgPayload()
sunEphemerisInMsg = messaging.EphemerisMsg().write(sunEphemerisInMsgData)
# subscribe input messages to module
module.navTransInMsg.subscribeTo(navTransInMsg)
module.navAttInMsg.subscribeTo(navAttInMsg)
module.asteroidEphemerisInMsg.subscribeTo(asteroidEphemerisInMsg)
module.sunEphemerisInMsg.subscribeTo(sunEphemerisInMsg)
# setup output message recorder objects
forceOutMsgRec = module.forceOutMsg.recorder()
unitTestSim.AddModelToTask(unitTaskName, forceOutMsgRec)
unitTestSim.InitializeSimulation()
unitTestSim.ConfigureStopTime(macros.sec2nano(0.))
unitTestSim.ExecuteSimulation()
if np.linalg.norm(forceOutMsgRec.forceRequestBody) >= 1e-8:
testFailCount += 1
testMessages.append("FAILED: " + module.ModelTag + " Module failed "
+ "force output" + " unit test")
if testFailCount == 0:
print("PASSED: " + module.ModelTag)
else:
print(testMessages)
return [testFailCount, "".join(testMessages)]
if __name__ == "__main__":
test_smallBodyWaypointFeedback(False)