Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/source/Support/bskReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ Version |release|
- Fixed bug with recording message payload entries that are 2D arrays. This bug was introduced with the faster recording
strategy added in version 2.8.0.
- Add a desired relative attitude between spacecraft in :ref:`constraintDynamicEffector`.
- Added new example scenarios demonstrating extended use of :ref:`constraintDynamicEffector`:
:ref:`scenarioConstrainedDynamicsManeuverAnalysis`, :ref:`scenarioConstrainedDynamicsComponentAnalysis`,
and :ref:`scenarioConstrainedDynamicsFrequencyAnalysis`.
- Added a new stepper motor simulation module :ref:`stepperMotor`. This kinematic profiler module is useful to
simulate the actuation of motor-driven prescribed spacecraft components.
- Made individual structures for each degree of freedom in :ref:`spinningBodyNDOFStateEffector` and
Expand Down
12 changes: 11 additions & 1 deletion examples/_default.rst
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,17 @@ It's recommended to study the first 6 scenarios in order:
Docking between Two CubeSats <mujoco/scenarioSimpleDocking>
Branching Panel Deployment with Locking Mechanisms <mujoco/scenarioBranchingPanels>

Constrained Spacecraft Dynamics Simulations
-------------------------------------------

.. toctree::
:maxdepth: 1

Two Spacecraft Connected Using Holonomic Constraints <scenarioConstrainedDynamics>
Constraint Gain Tuning Analysis With Maneuvers <scenarioConstrainedDynamicsManeuverAnalysis>
Constrained Motion Component Analysis Using a Truth Model <scenarioConstrainedDynamicsComponentAnalysis>
Frequency Analysis of Solar Panel Resonance Using the Constraint Effector <scenarioConstrainedDynamicsFrequencyAnalysis>

Complex Spacecraft Dynamics Simulations
---------------------------------------

Expand All @@ -231,7 +242,6 @@ Complex Spacecraft Dynamics Simulations
Spacecraft with 1- or 2-DOF Panel using single effector <scenarioSpinningBodiesTwoDOF>
Prescribed Motion Rotational Solar Array Deployment <scenarioDeployingSolarArrays>
Robotic Arm Effector with Profiler <scenarioRoboticArm>
Two Spacecraft Connected Using Holonomic Constraints <scenarioConstrainedDynamics>
Spacecraft with an multi-link extending component <scenarioExtendingBoom>

Mission Simulations
Expand Down
723 changes: 723 additions & 0 deletions examples/scenarioConstrainedDynamicsComponentAnalysis.py

Large diffs are not rendered by default.

513 changes: 513 additions & 0 deletions examples/scenarioConstrainedDynamicsFrequencyAnalysis.py

Large diffs are not rendered by default.

531 changes: 531 additions & 0 deletions examples/scenarioConstrainedDynamicsManeuverAnalysis.py

Large diffs are not rendered by default.

79 changes: 79 additions & 0 deletions src/tests/test_scenarioConstrainedDynamicsComponentAnalysis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#
# ISC License
#
# Copyright (c) 2025, 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.
#


#
# Basilisk Scenario Script and Integrated Test
#
# Purpose: Integrated test of scenarioConstrainedDynamicsComponentAnalysis
# Author: João Vaz Carneiro
# Creation Date: Oct. 2, 2025
#


import inspect
import os
import sys

import pytest
from Basilisk.utilities import unitTestSupport

# Get current file path
filename = inspect.getframeinfo(inspect.currentframe()).filename
path = os.path.dirname(os.path.abspath(filename))

sys.path.append(path + '/../../examples')
import scenarioConstrainedDynamicsComponentAnalysis


# uncomment this line is this test is to be skipped in the global unit test run, adjust message as needed
# @pytest.mark.skipif(conditionstring)
# uncomment this line if this test has an expected failure, adjust message as needed
# @pytest.mark.xfail(True)

# The following 'parametrize' function decorator provides the parameters and expected results for each
# of the multiple test runs for this test.
@pytest.mark.parametrize("component_list, sc_model", [(["panels"], "MEV2"), (["slosh"], "MEV2")])
@pytest.mark.scenarioTest
def test_scenarioConstrainedDynamicsComponentAnalysis(show_plots, component_list, sc_model):
'''This function is called by the py.test environment.'''
# each test method requires a single assert method to be called

testFailCount = 0 # zero unit test result counter
testMessages = [] # create empty array to store test log messages

try:
figureList = scenarioConstrainedDynamicsComponentAnalysis.run(show_plots, component_list, sc_model)
# save the figures to the Doxygen scenario images folder
for pltName, plt in list(figureList.items()):
unitTestSupport.saveScenarioFigure(pltName, plt, path)

except OSError as err:
testFailCount += 1
testMessages.append("scenarioConstrainedDynamicsComponentAnalysis test are failed.")

# print out success message if no error were found
if testFailCount == 0:
print("PASSED ")
else:
print(testFailCount)
print(testMessages)

# each test method requires a single assert method to be called
# this check below just makes sure no sub-test failures were found
assert testFailCount < 1, testMessages
79 changes: 79 additions & 0 deletions src/tests/test_scenarioConstrainedDynamicsFrequencyAnalysis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#
# ISC License
#
# Copyright (c) 2025, 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.
#


#
# Basilisk Scenario Script and Integrated Test
#
# Purpose: Integrated test of scenarioConstrainedDynamicsFrequencyAnalysis
# Author: João Vaz Carneiro
# Creation Date: Oct. 2, 2025
#


import inspect
import os
import sys

import pytest
from Basilisk.utilities import unitTestSupport

# Get current file path
filename = inspect.getframeinfo(inspect.currentframe()).filename
path = os.path.dirname(os.path.abspath(filename))

sys.path.append(path + '/../../examples')
import scenarioConstrainedDynamicsFrequencyAnalysis


# uncomment this line is this test is to be skipped in the global unit test run, adjust message as needed
# @pytest.mark.skipif(conditionstring)
# uncomment this line if this test has an expected failure, adjust message as needed
# @pytest.mark.xfail(True)

# The following 'parametrize' function decorator provides the parameters and expected results for each
# of the multiple test runs for this test.
@pytest.mark.parametrize("gain_list, sc_model", [([1E1, 1E2, 1E3, 1E4, 1E5], "MEV2")])
@pytest.mark.scenarioTest
def test_scenarioConstrainedDynamicsFrequencyAnalysis(show_plots, gain_list, sc_model):
'''This function is called by the py.test environment.'''
# each test method requires a single assert method to be called

testFailCount = 0 # zero unit test result counter
testMessages = [] # create empty array to store test log messages

try:
figureList = scenarioConstrainedDynamicsFrequencyAnalysis.run(show_plots, gain_list, sc_model)
# save the figures to the Doxygen scenario images folder
for pltName, plt in list(figureList.items()):
unitTestSupport.saveScenarioFigure(pltName, plt, path)

except OSError as err:
testFailCount += 1
testMessages.append("scenarioConstrainedDynamicsFrequencyAnalysis test are failed.")

# print out success message if no error were found
if testFailCount == 0:
print("PASSED ")
else:
print(testFailCount)
print(testMessages)

# each test method requires a single assert method to be called
# this check below just makes sure no sub-test failures were found
assert testFailCount < 1, testMessages
81 changes: 81 additions & 0 deletions src/tests/test_scenarioConstraintDynamicsManeuverAnalysis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#
# ISC License
#
# Copyright (c) 2025, 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.
#


#
# Basilisk Scenario Script and Integrated Test
#
# Purpose: Integrated test of scenarioConstrainedDynamicsManeuverAnalysis
# Author: Andrew Morell
# Creation Date: Oct. 4, 2025
#


import inspect
import os
import sys

import pytest
from Basilisk.utilities import unitTestSupport

# Get current file path
filename = inspect.getframeinfo(inspect.currentframe()).filename
path = os.path.dirname(os.path.abspath(filename))

sys.path.append(path + '/../../examples')
import scenarioConstrainedDynamicsManeuverAnalysis


# uncomment this line is this test is to be skipped in the global unit test run, adjust message as needed
# @pytest.mark.skipif(conditionstring)
# uncomment this line if this test has an expected failure, adjust message as needed
# @pytest.mark.xfail(True)

# The following 'parametrize' function decorator provides the parameters and expected results for each
# of the multiple test runs for this test.
@pytest.mark.parametrize("gain_list, relpos_config, orbit_config, maneuver_config, sc_model",
[([1E1, 1E2, 1E3], "alongtrackahead", "LEO", "attitude", "MEV2"),
([1E1, 1E2, 1E3], "alongtrackahead", "LEO", "orbit", "MEV2")])
@pytest.mark.scenarioTest
def test_scenarioConstrainedDynamicsManeuverAnalysis(show_plots, gain_list, relpos_config, orbit_config, maneuver_config, sc_model):
'''This function is called by the py.test environment.'''
# each test method requires a single assert method to be called

testFailCount = 0 # zero unit test result counter
testMessages = [] # create empty array to store test log messages

try:
figureList = scenarioConstrainedDynamicsManeuverAnalysis.run(show_plots, gain_list, relpos_config, orbit_config, maneuver_config, sc_model)
# save the figures to the Doxygen scenario images folder
for pltName, plt in list(figureList.items()):
unitTestSupport.saveScenarioFigure(pltName, plt, path)

except OSError as err:
testFailCount += 1
testMessages.append("scenarioConstrainedDynamicsManeuverAnalysis test are failed.")

# print out success message if no error were found
if testFailCount == 0:
print("PASSED ")
else:
print(testFailCount)
print(testMessages)

# each test method requires a single assert method to be called
# this check below just makes sure no sub-test failures were found
assert testFailCount < 1, testMessages