Skip to content

Commit 2c70bc8

Browse files
committed
[#144] Integrated RSO environment test
1 parent 2191399 commit 2c70bc8

2 files changed

Lines changed: 126 additions & 3 deletions

File tree

src/bsk_rl/act/continuous_actions.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,7 @@ def set_action(self, action: np.ndarray) -> None:
137137
)
138138
if dt != dt_desired:
139139
self.satellite.logger.warning(
140-
f"Requested drift duration {dt_desired} out of range. "
141-
f"Clamping to {dt}."
140+
f"Requested drift duration {dt_desired} out of range. Clamping to {dt}."
142141
)
143142

144143
self.satellite.logger.info(
@@ -153,7 +152,7 @@ def set_action(self, action: np.ndarray) -> None:
153152
# TODO: should wait until action_impulsive_thrust is done if not immediate
154153
if self.fsw_action is not None:
155154
getattr(self.satellite.fsw, self.fsw_action)()
156-
self.satellite.log_info(f"FSW action {self.fsw_action} activated.")
155+
self.satellite.logger.info(f"FSW action {self.fsw_action} activated.")
157156

158157

159158
class ImpulsiveThrustHill(ImpulsiveThrust):
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import types
2+
from functools import partial
3+
4+
import numpy as np
5+
import pytest
6+
7+
from bsk_rl import ConstellationTasking, act, data, obs, sats, scene
8+
from bsk_rl.obs.relative_observations import rso_imaged_regions
9+
from bsk_rl.sim import dyn, fsw
10+
from bsk_rl.utils.orbital import fibonacci_sphere, random_circular_orbit
11+
12+
13+
class RSOSat(sats.Satellite):
14+
observation_spec = [
15+
obs.SatProperties(dict(prop="one", fn=lambda _: 1.0)),
16+
]
17+
action_spec = [act.Drift(duration=1e9)]
18+
dyn_type = dyn.RSODynModel
19+
fsw_type = fsw.BasicFSWModel
20+
21+
22+
class InspectorSat(sats.Satellite):
23+
observation_spec = [
24+
obs.RelativeProperties(
25+
dict(
26+
prop="rso_imaged_regions",
27+
fn=partial(
28+
rso_imaged_regions,
29+
region_centers=fibonacci_sphere(15),
30+
frame="chief_hill",
31+
),
32+
),
33+
chief_name="RSO",
34+
),
35+
obs.Eclipse(),
36+
]
37+
action_spec = [
38+
act.ImpulsiveThrustHill(
39+
chief_name="RSO",
40+
max_dv=1.0,
41+
max_drift_duration=5700.0 * 2,
42+
fsw_action="action_inspect_rso",
43+
)
44+
]
45+
dyn_type = types.new_class("Dyn", (dyn.MaxRangeDynModel, dyn.RSOInspectorDynModel))
46+
fsw_type = types.new_class(
47+
"FSW",
48+
(
49+
fsw.SteeringFSWModel,
50+
fsw.MagicOrbitalManeuverFSWModel,
51+
fsw.RSOInspectorFSWModel,
52+
),
53+
)
54+
55+
56+
def inspector_sat_args(**kwargs):
57+
return dict(
58+
imageAttErrorRequirement=1.0,
59+
imageRateErrorRequirement=None,
60+
instrumentBaudRate=1,
61+
dataStorageCapacity=1e6,
62+
batteryStorageCapacity=1e9,
63+
storedCharge_Init=1e9,
64+
dv_available_init=10.0,
65+
chief_name="RSO",
66+
u_max=1.0,
67+
**kwargs,
68+
)
69+
70+
71+
@pytest.mark.repeat(10)
72+
def test_inspection():
73+
env = ConstellationTasking(
74+
satellites=[
75+
RSOSat(
76+
"RSO",
77+
sat_args=dict(oe=random_circular_orbit(i=0, alt=500, Omega=0, f=0)),
78+
),
79+
InspectorSat(
80+
"Inspector",
81+
sat_args=inspector_sat_args(
82+
oe=random_circular_orbit(i=0, alt=500.01, Omega=0, f=0)
83+
),
84+
obs_type=dict,
85+
),
86+
],
87+
scenario=scene.SphericalRSO(
88+
n_points=100,
89+
radius=1.0,
90+
theta_max=np.radians(90), # Generous observation angle
91+
range_max=250,
92+
theta_solar_max=np.radians(90), # Generous illumination angle
93+
),
94+
rewarder=(data.RSOInspectionReward()),
95+
time_limit=60000,
96+
sim_rate=1.0,
97+
# log_level="INFO",
98+
)
99+
100+
observation, _ = env.reset()
101+
in_eclipse_start = (
102+
observation["Inspector"]["eclipse"][0] > observation["Inspector"]["eclipse"][1]
103+
)
104+
105+
duration = 100
106+
observation, reward, _, _, _ = env.step(
107+
dict(RSO=0, Inspector=[0.0, 0.0, 0.0, duration])
108+
)
109+
in_eclipse_end = (
110+
observation["Inspector"]["eclipse"][0] > observation["Inspector"]["eclipse"][1]
111+
)
112+
113+
# Check that nothing is imaged in eclipse
114+
if in_eclipse_start and in_eclipse_end:
115+
assert sum(observation["Inspector"]["rel_props"]["rso_imaged_regions"]) == 0
116+
else:
117+
# Orbital setup means that if not in eclipse, inspector is on the illuminated side
118+
assert sum(observation["Inspector"]["rel_props"]["rso_imaged_regions"]) > 0
119+
120+
# Check that reward was yielded correctly
121+
if sum(observation["Inspector"]["rel_props"]["rso_imaged_regions"] > 0):
122+
assert reward["Inspector"] > 0
123+
else:
124+
assert "Inspector" not in reward or reward["Inspector"] == 0

0 commit comments

Comments
 (0)