From 32d22a4dca322d4bdc69906e57195a577ef21711 Mon Sep 17 00:00:00 2001 From: Mark Stephenson Date: Fri, 11 Jul 2025 11:25:47 -0700 Subject: [PATCH 1/2] [#298] Two way range checking --- docs/source/release_notes.rst | 2 ++ src/bsk_rl/sim/dyn/relative_motion.py | 28 ++++++++++++++++++++-- tests/integration/sim/test_int_dynamics.py | 13 ++++++++-- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/docs/source/release_notes.rst b/docs/source/release_notes.rst index c6cc7a68..14f27469 100644 --- a/docs/source/release_notes.rst +++ b/docs/source/release_notes.rst @@ -51,6 +51,8 @@ Development - |version| overwritten. * Add the ability to define metaagents that concatenate satellite action and observation spaces in the environment. +* Add the ability to have the chief also terminate if a deputy violates a maximum range + constraint in :class:`~bsk_rl.sim.dyn.MaxRangeDynModel`. Version 1.1.0 diff --git a/src/bsk_rl/sim/dyn/relative_motion.py b/src/bsk_rl/sim/dyn/relative_motion.py index bd3a7bc5..482327ab 100644 --- a/src/bsk_rl/sim/dyn/relative_motion.py +++ b/src/bsk_rl/sim/dyn/relative_motion.py @@ -1,5 +1,7 @@ """Dynamics models concerning the relative motion of spacecraft.""" +import types + import numpy as np from Basilisk.simulation import spacecraftLocation from Basilisk.utilities import macros @@ -152,13 +154,21 @@ def range_valid(self) -> bool: """Check if conjunction has not occurred.""" return len(self.out_of_ranges) == 0 - @default_args(max_range_radius=5000, chief_name=None) - def setup_range(self, max_range_radius: float, chief_name: str, **kwargs) -> None: + @default_args(max_range_radius=5000, chief_name=None, enforce_range_on_chief=False) + def setup_range( + self, + max_range_radius: float, + chief_name: str, + enforce_range_on_chief: bool, + **kwargs, + ) -> None: """Set up maximum distance checking relative to a chief satellite. Args: max_range_radius: [m] Maximum allowed range from the chief satellite. chief_name: Chief satellite to check range against. + enforce_range_on_chief: If True, the chief will also die if the range is + violated by this satellite. kwargs: Passed to other setup functions. """ self.max_range_radius = max_range_radius @@ -173,6 +183,20 @@ def setup_range(self, max_range_radius: float, chief_name: str, **kwargs) -> Non self.chief = self.simulator.get_satellite(self.chief_name) + # Add range check to chief if required + if enforce_range_on_chief: + + @aliveness_checker + def range_valid(self, deputy=self): + return deputy.range_valid() + + setattr( + self.chief.dynamics, + valid_func_name(f"range_valid_{self.satellite.name}"), + types.MethodType(range_valid, self.chief.dynamics), + ) + + # Add event to check for max range violation def condition(sim): distance = np.linalg.norm( np.array(self.satellite.dynamics.r_BN_N) diff --git a/tests/integration/sim/test_int_dynamics.py b/tests/integration/sim/test_int_dynamics.py index 6a28e9ef..bb5af5d6 100644 --- a/tests/integration/sim/test_int_dynamics.py +++ b/tests/integration/sim/test_int_dynamics.py @@ -174,7 +174,8 @@ class TestMaxRangeDynModel: ([0, 1e8, 0], [1e8, 0, 0], True), ], ) - def test_max_range(self, rN1, rN2, max_range_violation): + @pytest.mark.parametrize("fail_chief", [True, False]) + def test_max_range(self, rN1, rN2, max_range_violation, fail_chief): class ChiefSat(sats.Satellite): fsw_type = fsw.BasicFSWModel dyn_type = dyn.BasicDynamicsModel @@ -206,6 +207,7 @@ class DeputySat(sats.Satellite): oe=None, chief_name="Chief", max_range_radius=100, + enforce_range_on_chief=fail_chief, ), ), ], @@ -217,12 +219,19 @@ class DeputySat(sats.Satellite): env.reset() - env.step(dict(Chief=0, Deputy=0)) + _, _, terminated, _, _ = env.step(dict(Chief=0, Deputy=0)) sat1 = env.unwrapped.satellites[0] sat2 = env.unwrapped.satellites[1] if max_range_violation: assert sat2.dynamics.out_of_ranges == [sat1] + assert terminated["Deputy"] + if fail_chief: + assert terminated["Chief"] + else: + assert not terminated["Chief"] else: assert sat2.dynamics.out_of_ranges == [] + assert not terminated["Chief"] + assert not terminated["Deputy"] From 229e226f2296bf643c84b5198e8398b80796e958 Mon Sep 17 00:00:00 2001 From: Mark Stephenson Date: Wed, 23 Jul 2025 16:38:35 -0700 Subject: [PATCH 2/2] [#300] Fix t=0 failure logging --- src/bsk_rl/sim/simulator.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bsk_rl/sim/simulator.py b/src/bsk_rl/sim/simulator.py index 363995b9..93f42b96 100644 --- a/src/bsk_rl/sim/simulator.py +++ b/src/bsk_rl/sim/simulator.py @@ -66,8 +66,7 @@ def finish_init(self) -> None: """Finish simulator initialization.""" self.set_vizard_epoch() self.InitializeSimulation() - self.ConfigureStopTime(0) - self.ExecuteSimulation() + self.TotalSim.StepUntilStop(0, -1) @property def sim_time_ns(self) -> int: