Broadcast Communication
By default, communication occurs between all satellites that are specified by the communication method. This tutorial shows how to use two classes to configure a broadcast action that must be taken for communication to occur:
Broadcast, which gives satellites an action that enables communication from them at the end of the current step.
BroadcastCommunication, which can be combined with another communication method to limit communication from broadcasters to those satellites satisfying the requirements of the other communication method.
Configuring the Environment
For this example, a multisatellite target imaging environment will be used. The goal is to maximize the value of unique images taken. This configuration is similar to the Multi-Agent Environments example.
[1]:
from typing import ClassVar
from bsk_rl import act, comm, data, obs, sats, scene
from bsk_rl.sim import dyn, fsw
class ImagingSatellite(sats.ImagingSatellite):
observation_spec: ClassVar[list[obs.Observation]] = [
obs.OpportunityProperties(
dict(prop="priority"),
dict(prop="opportunity_open", norm=5700.0),
n_ahead_observe=4,
)
]
action_spec: ClassVar[list[act.Action]] = [
act.Broadcast(duration=15.0),
act.Image(n_ahead_image=4),
]
dyn_type = dyn.FullFeaturedDynModel
fsw_type = fsw.SteeringImagerFSWModel
ACTION_BROADCAST = 0
ACTION_IMAGE_0 = 1
ACTION_IMAGE_1 = 2
ACTION_IMAGE_2 = 3
ACTION_IMAGE_3 = 4
Satellite properties are set to give the satellite near-unlimited power and storage resources. To randomize some parameters in a correlated manner across satellites, a sat_arg_randomizer is set and passed to the environment. In this case, the satellites are distributed in a trivial single-plane Walker-delta constellation.
[2]:
from bsk_rl.utils.orbital import walker_delta_args
N_AGENTS = 2
sat_args = dict(
imageAttErrorRequirement=0.01,
imageRateErrorRequirement=0.01,
batteryStorageCapacity=1e9,
storedCharge_Init=1e9,
dataStorageCapacity=1e12,
u_max=0.4,
K1=0.25,
K3=3.0,
omega_max=0.087,
servo_Ki=5.0,
servo_P=150 / 5,
)
sat_arg_randomizer = walker_delta_args(
altitude=800.0, inc=60.0, n_planes=1, clustersize=N_AGENTS, clusterspacing=5.0
)
A communication type is defined that uses multidegree line-of-sight communication with broadcasting.
[3]:
class BroadcastLOS(comm.BroadcastCommunication, comm.LOSMultiCommunication):
pass
Finally, the environment can be instantiated.
[4]:
from bsk_rl import ConstellationTasking
env = ConstellationTasking(
satellites=[ImagingSatellite(f"EO_{i + 1}", sat_args) for i in range(N_AGENTS)],
scenario=scene.UniformTargets(1000),
rewarder=data.UniqueImageReward(),
communicator=BroadcastLOS(),
sat_arg_randomizer=sat_arg_randomizer,
log_level="INFO",
)
_ = env.reset()
2026-11-09 20:08:34,415 gym INFO Resetting environment with seed=2587943372
2026-11-09 20:08:34,417 scene.targets INFO Generating 1000 targets
2026-11-09 20:08:34,470 sats.satellite.EO_1 INFO <0.00> EO_1: Finding opportunity windows from 0.00 to 600.00 seconds
2026-11-09 20:08:34,488 sats.satellite.EO_2 INFO <0.00> EO_2: Finding opportunity windows from 0.00 to 600.00 seconds
2026-11-09 20:08:34,505 gym INFO <0.00> Environment reset
In the first step, both agents are tasked with an imaging action, and one successfully images a target.
[5]:
_ = env.step({"EO_1": ACTION_IMAGE_3, "EO_2": ACTION_IMAGE_2})
2026-11-09 20:08:34,509 gym INFO <0.00> === STARTING STEP ===
2026-11-09 20:08:34,509 sats.satellite.EO_1 INFO <0.00> EO_1: target index 3 tasked
2026-11-09 20:08:34,509 sats.satellite.EO_1 INFO <0.00> EO_1: Target(tgt-930) tasked for imaging
2026-11-09 20:08:34,510 sats.satellite.EO_1 INFO <0.00> EO_1: Target(tgt-930) window enabled: 90.6 to 256.9
2026-11-09 20:08:34,510 sats.satellite.EO_1 INFO <0.00> EO_1: setting timed terminal event at 256.9
2026-11-09 20:08:34,511 sats.satellite.EO_2 INFO <0.00> EO_2: target index 2 tasked
2026-11-09 20:08:34,512 sats.satellite.EO_2 INFO <0.00> EO_2: Target(tgt-930) tasked for imaging
2026-11-09 20:08:34,512 sats.satellite.EO_2 INFO <0.00> EO_2: Target(tgt-930) window enabled: 1.3 to 173.2
2026-11-09 20:08:34,512 sats.satellite.EO_2 INFO <0.00> EO_2: setting timed terminal event at 173.2
2026-11-09 20:08:34,520 sats.satellite.EO_2 INFO <50.00> EO_2: imaged Target(tgt-930)
2026-11-09 20:08:34,520 data.base INFO <50.00> Total reward: {'EO_2': 0.9030882702791994}
2026-11-09 20:08:34,521 sats.satellite.EO_2 INFO <50.00> EO_2: Satellite EO_2 requires retasking
2026-11-09 20:08:34,523 gym INFO <50.00> Step reward: {'EO_2': 0.9030882702791994}
When both select the broadcast action, data is shared in both directions. This is subject to line-of-sight availability as well as selecting the correct action.
[6]:
_ = env.step({"EO_1": ACTION_BROADCAST, "EO_2": ACTION_BROADCAST})
2026-11-09 20:08:34,527 gym INFO <50.00> === STARTING STEP ===
2026-11-09 20:08:34,527 sats.satellite.EO_1 INFO <50.00> EO_1: action_broadcast tasked for 15.0 seconds
2026-11-09 20:08:34,527 sats.satellite.EO_1 INFO <50.00> EO_1: setting timed terminal event at 65.0
2026-11-09 20:08:34,528 sats.satellite.EO_2 INFO <50.00> EO_2: action_broadcast tasked for 15.0 seconds
2026-11-09 20:08:34,528 sats.satellite.EO_2 INFO <50.00> EO_2: setting timed terminal event at 65.0
2026-11-09 20:08:34,532 sats.satellite.EO_1 INFO <65.00> EO_1: timed termination at 65.0 for broadcast
2026-11-09 20:08:34,532 sats.satellite.EO_2 INFO <65.00> EO_2: timed termination at 65.0 for broadcast
2026-11-09 20:08:34,532 data.base INFO <65.00> Total reward: {}
2026-11-09 20:08:34,533 comm.communication INFO <65.00> Communicating data in 2 directions.
2026-11-09 20:08:34,533 comm.communication INFO <65.00> Optimizing data communication between all pairs of satellites
2026-11-09 20:08:34,534 sats.satellite.EO_1 INFO <65.00> EO_1: Satellite EO_1 requires retasking
2026-11-09 20:08:34,534 sats.satellite.EO_2 INFO <65.00> EO_2: Satellite EO_2 requires retasking
2026-11-09 20:08:34,536 gym INFO <65.00> Step reward: {}
One agent can broadcast while the others are completing a different task.
[7]:
_ = env.step({"EO_1": ACTION_IMAGE_2, "EO_2": ACTION_BROADCAST}) # Agent 1 broadcasts
2026-11-09 20:08:34,539 gym INFO <65.00> === STARTING STEP ===
2026-11-09 20:08:34,540 sats.satellite.EO_1 INFO <65.00> EO_1: target index 2 tasked
2026-11-09 20:08:34,540 sats.satellite.EO_1 INFO <65.00> EO_1: Target(tgt-642) tasked for imaging
2026-11-09 20:08:34,541 sats.satellite.EO_1 INFO <65.00> EO_1: Target(tgt-642) window enabled: 131.8 to 341.0
2026-11-09 20:08:34,541 sats.satellite.EO_1 INFO <65.00> EO_1: setting timed terminal event at 341.0
2026-11-09 20:08:34,542 sats.satellite.EO_2 INFO <65.00> EO_2: action_broadcast tasked for 15.0 seconds
2026-11-09 20:08:34,542 sats.satellite.EO_2 INFO <65.00> EO_2: setting timed terminal event at 80.0
2026-11-09 20:08:34,545 sats.satellite.EO_2 INFO <80.00> EO_2: timed termination at 80.0 for broadcast
2026-11-09 20:08:34,546 data.base INFO <80.00> Total reward: {}
2026-11-09 20:08:34,546 comm.communication INFO <80.00> Communicating data in 1 direction.
2026-11-09 20:08:34,547 sats.satellite.EO_2 INFO <80.00> EO_2: Satellite EO_2 requires retasking
2026-11-09 20:08:34,549 gym INFO <80.00> Step reward: {}