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: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,6 @@ target/
# Jupyter Notebook
.ipynb_checkpoints

# PDFs and Images
*.jpg

# pyenv
.python-version

Expand Down
26 changes: 25 additions & 1 deletion docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,31 @@ for working with these environments.
A whitepaper on the design philosophy behind BSK-RL and an example use case can be
:download:`downloaded here <_static/stephenson_bskrl_2024.pdf>`.

.. youtube:: 8qR-AGrCFQw
Capabilities
------------

Earth Observation
^^^^^^^^^^^^^^^^^

.. youtube:: lCN0TiNJ1i4

.. youtube:: 4orleGCi7n0

|

Spacecraft Inspection
^^^^^^^^^^^^^^^^^^^^^

.. youtube:: eQEoTOYADKc

|

Space Domain Awareness
^^^^^^^^^^^^^^^^^^^^^^

.. youtube:: Aas0z43uS9M

|

Quickstart
----------
Expand Down
6 changes: 6 additions & 0 deletions docs/source/release_notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ Development - |version|
* Add ``bsk`` as a dependency in ``pyproject.toml``.
* Update the CI/CD workflows to build BSK-RL using the new ``bsk`` dependency.
* Optimize performance of AEOS environments, especially for high request counts.
* Allow for the Vizard output path to be specified as a .bin file instead of just a directory.
* Use Vizard 2.3.1 locations for visualization; results in significantly smaller output
files.
* Allow for a simpler Earth model to be used in Vizard by setting ``use_simple_earth=True``
in the Vizard settings dictionary. This is helpful for when visualizing may Earth-fixed
targets.


Version 1.2.0
Expand Down
23 changes: 13 additions & 10 deletions examples/fault_environment.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@
" satellite.simulator.createNewEvent(\n",
" f\"add{self.name}Fault\",\n",
" satellite.dynamics.dyn_rate,\n",
" True,\n",
" [f\"self.TotalSim.CurrentNanos>={self.time}\"],\n",
" [\n",
" eventActive=True,\n",
" conditionTime=self.time,\n",
" actionList=[\n",
" f\"self.faultList[{self.uniqueFaultIdx}].execute({satellite._satellite_command})\",\n",
" f\"self.faultList[{self.uniqueFaultIdx}].print({satellite._satellite_command})\",\n",
" ],\n",
Expand Down Expand Up @@ -114,9 +114,9 @@
"\n",
" def print(self, satellite):\n",
" if self.wheelIdx == \"all\":\n",
" self.message = f\"RW Power Fault: all RW's power limit reduced to {self.reducedLimit} Watts at {self.time*macros.NANO2MIN} minutes!\"\n",
" self.message = f\"RW Power Fault: all RW's power limit reduced to {self.reducedLimit} Watts at {self.time * macros.NANO2MIN} minutes!\"\n",
" else:\n",
" self.message = f\"RW Power Fault: RW{self.wheelIdx}'s power limit reduced to {self.reducedLimit} Watts at {self.time*macros.NANO2MIN} minutes!\"\n",
" self.message = f\"RW Power Fault: RW{self.wheelIdx}'s power limit reduced to {self.reducedLimit} Watts at {self.time * macros.NANO2MIN} minutes!\"\n",
" super().print_message(self.message, satellite)"
]
},
Expand All @@ -135,7 +135,6 @@
"outputs": [],
"source": [
"class CustomDynModel(dyn.FullFeaturedDynModel):\n",
"\n",
" @property\n",
" def solar_angle_norm(self) -> float:\n",
" sun_vec_N = (\n",
Expand Down Expand Up @@ -283,8 +282,8 @@
" for i in range(4):\n",
" rwConfigElementMsg = messaging.RWConfigElementMsgPayload()\n",
" rwConfigElementMsg.gsHat_B = self.dynamics.Gs[:, i]\n",
" rwConfigElementMsg.Js = self.dynamics.rwFactory.rwList[f\"RW{i+1}\"].Js\n",
" rwConfigElementMsg.uMax = self.dynamics.rwFactory.rwList[f\"RW{i+1}\"].u_max\n",
" rwConfigElementMsg.Js = self.dynamics.rwFactory.rwList[f\"RW{i + 1}\"].Js\n",
" rwConfigElementMsg.uMax = self.dynamics.rwFactory.rwList[f\"RW{i + 1}\"].u_max\n",
" rwConfigElementList.append(rwConfigElementMsg)\n",
" rwConstellationConfig.reactionWheels = rwConfigElementList\n",
" self.rwConstellationConfigInMsg = messaging.RWConstellationMsg().write(\n",
Expand Down Expand Up @@ -544,7 +543,6 @@
"source": [
"total_reward = 0.0\n",
"while True:\n",
"\n",
" observation, reward, terminated, truncated, info = env.step(\n",
" env.action_space.sample()\n",
" )\n",
Expand All @@ -558,6 +556,11 @@
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
Expand All @@ -568,7 +571,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.12"
"version": "3.12.10"
}
},
"nbformat": 4,
Expand Down
Binary file added src/bsk_rl/_dat/world.200407.3x5400x2700.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
91 changes: 42 additions & 49 deletions src/bsk_rl/data/rso_inspection.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def get_log_state(self) -> Optional[tuple[list[list[bool]], list[list[bool]]]]:
return inspected_logs, illuminated_logs

def compare_log_states(self, _, logs) -> RSOInspectionData:
"""Identify point status and update their colors in Vizard."""
"""Identify point status."""
if self.role == RSO:
return RSOInspectionData()

Expand All @@ -161,61 +161,13 @@ def compare_log_states(self, _, logs) -> RSOInspectionData:
if any(log):
point_illuminate_status[rso_point] = True

self.update_point_colors(
self.data.point_illuminate_status.keys(),
color="gray",
)
self.update_point_colors(
[
rso_point
for rso_point in point_illuminate_status
if point_illuminate_status[rso_point]
],
color="yellow",
)
self.update_point_colors(
[
rso_point
for rso_point in point_inspect_status
if point_inspect_status[rso_point]
],
color="chartreuse",
permanent=True,
)

if len(point_inspect_status) > 0:
self.satellite.logger.info(
f"Inspected {len(point_inspect_status)} points this step"
)

return RSOInspectionData(point_inspect_status, point_illuminate_status)

@vizard.visualize
def update_point_colors(
self,
rso_points,
color,
alpha=0.5,
permanent=False,
vizInstance=None,
vizSupport=None,
):
"""Update target colors in Vizard."""
if not hasattr(self, "permanent_point_colors"):
self.permanent_point_colors = []

for location in vizInstance.locations:
if (
location.stationName not in self.permanent_point_colors
and location.stationName in [str(point) for point in rso_points]
):
if not all(
np.equal(location.color, vizSupport.toRGBA255(color, alpha=alpha))
):
location.color = vizSupport.toRGBA255(color, alpha=alpha)
if permanent:
self.permanent_point_colors.append(location.stationName)


class RSOInspectionReward(GlobalReward):
data_store_type = RSOInspectionDataStore
Expand Down Expand Up @@ -286,6 +238,43 @@ def initial_data(self, satellite: Satellite) -> RSOInspectionData:
{point: False for point in self.scenario.rso_points},
)

@vizard.visualize
def determine_point_colors(self, total_data, new_data_dict):
"""Determine target colors in Vizard."""
colors = ["grey"] * len(self.scenario.rso_points)
for i, point in enumerate(self.scenario.rso_points):
if any(
[
data.point_illuminate_status.get(point, False)
for data in new_data_dict.values()
]
):
colors[i] = "yellow"
if total_data.point_inspect_status.get(point, False):
colors[i] = "chartreuse"

return colors

@vizard.visualize
def update_point_colors(
self,
rso_points,
colors,
alpha=0.5,
vizInstance=None,
vizSupport=None,
):
"""Update target colors in Vizard."""
if not hasattr(self, "prev_colors"):
self.prev_colors = [None] * len(colors)

for point, color, prev_color in zip(rso_points, colors, self.prev_colors):
color_vec = vizSupport.toRGBA255(color, alpha=alpha)
if prev_color != color:
vizSupport.changeLocation(vizInstance, str(point), color=color_vec)

self.prev_colors = colors

def calculate_reward(
self, new_data_dict: dict[str, RSOInspectionData]
) -> dict[str, float]:
Expand All @@ -307,6 +296,10 @@ def calculate_reward(
)
total_data += data

# Plot inspection status in Vizard
colors = self.determine_point_colors(total_data, new_data_dict)
self.update_point_colors(self.scenario.rso_points, colors)

# Check for completion bonus
logger.info(
f"Inspected/Illuminated/Total: {total_data.num_points_inspected}/{total_data.num_points_illuminated}/{total_points}"
Expand Down
9 changes: 6 additions & 3 deletions src/bsk_rl/data/unique_image_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,12 @@ def compare_log_states(
@vizard.visualize
def update_target_colors(self, targets, vizInstance=None, vizSupport=None):
"""Update target colors in Vizard."""
for location in vizInstance.locations:
if location.stationName in [target.name for target in targets]:
location.color = vizSupport.toRGBA255(self.satellite.vizard_color)
for target in targets:
vizSupport.changeLocation(
vizInstance,
target.name,
color=vizSupport.toRGBA255(self.satellite.vizard_color),
)


class UniqueImageReward(GlobalReward):
Expand Down
12 changes: 7 additions & 5 deletions src/bsk_rl/gym.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,17 +123,19 @@ def __init__(
modules will be imported.
vizard_settings: Settings for Vizard visualization. Set in ``vizIstance.settings``.
Additionally, the key ``vizard_rate`` can be set to the rate at which Vizard updates.
Valid setting can be found `here <https://hanspeterschaub.info/basilisk/Vizard/vizardAdvanced/vizardSettings.html#id1>`_.
The key ``use_simple_earth`` can be set to use a lower detail Earth shader
that may help viewing ground locations. Other settings can be found
`in the Basilisk documentation <https://avslab.github.io/basilisk/Vizard/vizardAdvanced/vizardSettings.html#id1>`_.
render_mode: Unused.
"""
self.seed = None
self._configure_logging(log_level, log_dir)
if vizard_dir is not None:
vizard.VIZARD_PATH = vizard_dir
if vizard_settings is not None:
logger.warning(
"Vizard settings provided but Vizard is not enabled. Ignoring settings."
)
if vizard_settings is not None and vizard_dir is None:
logger.warning(
"Vizard settings provided but Vizard is not enabled. Ignoring settings."
)
self.vizard_settings = vizard_settings if vizard_settings is not None else {}

if isinstance(satellites, Satellite):
Expand Down
2 changes: 1 addition & 1 deletion src/bsk_rl/sats/satellite.py
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ def side_effect(sim):
self._timed_terminal_event_name,
macros.sec2nano(self.simulator.sim_rate),
True,
conditionFunction=lambda sim: sim.sim_time >= t_close,
conditionTime=macros.sec2nano(t_close),
actionFunction=side_effect,
terminal=self.variable_interval,
)
Expand Down
1 change: 1 addition & 0 deletions src/bsk_rl/scene/targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ def visualize_target(self, target, vizSupport=None, vizInstance=None):
fieldOfView=np.arctan(500 / 800),
color=vizSupport.toRGBA255("white"),
range=1000.0 * 1000, # meters
markerScale=np.sqrt(target.priority),
)
if vizInstance.settings.showLocationCones == 0:
vizInstance.settings.showLocationCones = -1
Expand Down
Loading