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
2 changes: 2 additions & 0 deletions docs/source/release_notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
28 changes: 26 additions & 2 deletions src/bsk_rl/sim/dyn/relative_motion.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand Down
3 changes: 1 addition & 2 deletions src/bsk_rl/sim/simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
13 changes: 11 additions & 2 deletions tests/integration/sim/test_int_dynamics.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -206,6 +207,7 @@ class DeputySat(sats.Satellite):
oe=None,
chief_name="Chief",
max_range_radius=100,
enforce_range_on_chief=fail_chief,
),
),
],
Expand All @@ -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"]