async def simulation_timepulse_propagate(message, nats_handler, shared_storage, logger): """ Propagates the satellites current orbit and attitude Args: message (natsmessage): message message.data dictionary with structure as described in message_structure.json message.data["time"] is the time update nats_handler (natsHandler): distributes callbacks according to the message subject shared_storage: dictionary containing information on on the entire swarm, the time, and the particular satellites phonebook """ # Distance that will prevent satellites from communicating max_range = shared_storage["range"] # Updating time shared_storage["time"] = message.data["time"] cubesat_id = nats_handler.sender_id # Making a propagator for satellite running this service self_orbit_propagator = orekit_utils.analytical_propagator( shared_storage["swarm"][cubesat_id]["orbit"]) # Each satellite's state will be upated and the phonebook will be updated for satellite in shared_storage["swarm"]: # Info about each satellite state is accessed to propagate orbit and attitude orbit_propagator = orekit_utils.analytical_propagator( shared_storage["swarm"][satellite]["orbit"]) attitude = shared_storage["swarm"][satellite]["orbit"]["attitude"] attitude_param = dict() frame = shared_storage["swarm"][satellite]["orbit"]["frame"] # Info about satellite attitude is accessed if attitude in shared_storage["swarm"]: attitude_provider_type = orekit_utils.utils.MOVING_BODY_TRACKING attitude_param = shared_storage["swarm"][attitude]["orbit"] elif attitude in shared_storage["grstns"]: attitude_provider_type = orekit_utils.utils.GROUND_TRACKING attitude_param = shared_storage["grstns"][attitude]["location"] elif attitude in shared_storage["iots"]: attitude_provider_type = orekit_utils.utils.GROUND_TRACKING attitude_param = shared_storage["iots"][attitude]["location"] elif attitude == orekit_utils.utils.NADIR_TRACKING: attitude_provider_type = attitude else: raise Exception("attitude unknown") # storing/updating reference frame attitude_param["frame"] = frame # constructing a attitude provider from info gathered above attitude_provider = orekit_utils.attitude_provider_constructor( attitude_provider_type, attitude_param) # the orbit propagator and attitude provider are consolidated orbit_propagator.setAttitudeProvider(attitude_provider) time = orekit_utils.absolute_time_converter_utc_string( shared_storage["time"]) # new satellite state containg attitude and orbit info new_state = orbit_propagator.propagate(time) # the shared storage is updated as necessary shared_storage["swarm"][satellite][ "orbit"] = orekit_utils.get_keplerian_parameters(new_state) shared_storage["swarm"][satellite]["orbit"].update({"frame": frame}) shared_storage["swarm"][satellite]["orbit"].update( {"attitude": attitude}) shared_storage["swarm"][satellite][ "last_update_time"] = shared_storage["time"] # Checking if the satellites target is in view and upating shared storage accordingly if attitude_provider_type == orekit_utils.utils.GROUND_TRACKING: shared_storage["swarm"][satellite][ "target_in_view"] = orekit_utils.check_iot_in_range( orbit_propagator, attitude_param["latitude"], attitude_param["longitude"], attitude_param["altitude"], time) elif attitude_provider_type == orekit_utils.utils.NADIR_TRACKING: shared_storage["swarm"][satellite]["target_in_view"] = True elif attitude_provider_type == orekit_utils.utils.MOVING_BODY_TRACKING: tracked_propagator = orekit_utils.analytical_propagator( attitude_param) shared_storage["swarm"][satellite][ "target_in_view"] = orekit_utils.visible_above_horizon( orbit_propagator, tracked_propagator, time) else: raise Exception("attitude_provider unknown") # Updating phonebook based on the location of the satellites if satellite != cubesat_id: cur_orbit_propagator = orekit_utils.analytical_propagator( shared_storage["swarm"][satellite]["orbit"]) time = orekit_utils.absolute_time_converter_utc_string( shared_storage["time"]) distance = orekit_utils.find_sat_distance(self_orbit_propagator, cur_orbit_propagator, time) if distance < max_range and orekit_utils.visible_above_horizon( self_orbit_propagator, cur_orbit_propagator, time): shared_storage["sat_phonebook"][satellite] = True else: shared_storage["sat_phonebook"][satellite] = False # Message contaning data on the updated state of a satellite is sent for each sent for sat_id in shared_storage["swarm"]: msg = nats_handler.create_message( {"state": { sat_id: shared_storage["swarm"][sat_id] }}, MessageSchemas.STATE_MESSAGE) subject = "state" await nats_handler.send_message(subject, msg) # The satellites updated phonebook is sent sat_phonebook_message = nats_handler.create_message( shared_storage["sat_phonebook"], MessageSchemas.PHONEBOOK_MESSAGE) await nats_handler.send_message("internal.phonebook", sat_phonebook_message) # IOT PHONEBOOK UPDATER for iot_id in shared_storage["iots"]: latitude = shared_storage["iots"][iot_id]["location"]["latitude"] longitude = shared_storage["iots"][iot_id]["location"]["longitude"] altitude = shared_storage["iots"][iot_id]["location"]["altitude"] if orekit_utils.check_iot_in_range( self_orbit_propagator, latitude, longitude, altitude, orekit_utils.absolute_time_converter_utc_string( shared_storage["time"])): shared_storage["iot_phonebook"][iot_id] = True else: shared_storage["iot_phonebook"][iot_id] = False # Sending updated phonebook iot_phonebook_message = nats_handler.create_message( shared_storage["iot_phonebook"], MessageSchemas.PHONEBOOK_MESSAGE) await nats_handler.send_message("internal.iot_phonebook", iot_phonebook_message) #Groundstation Phonebook Updater for ground_id in shared_storage["grstns"]: latitude = shared_storage["grstns"][ground_id]["location"]["latitude"] longitude = shared_storage["grstns"][ground_id]["location"][ "longitude"] altitude = shared_storage["grstns"][ground_id]["location"]["altitude"] if orekit_utils.check_iot_in_range( self_orbit_propagator, latitude, longitude, altitude, orekit_utils.absolute_time_converter_utc_string( shared_storage["time"])): shared_storage["grstn_phonebook"][ground_id] = True else: shared_storage["grstn_phonebook"][ground_id] = False # Sending updated phonebook grstn_phonebook_message = nats_handler.create_message( shared_storage["grstn_phonebook"], MessageSchemas.PHONEBOOK_MESSAGE) await nats_handler.send_message("internal.grnst_phonebook", grstn_phonebook_message)
def test_attitude_provider_constructor(self): """ attitude_provider_constructor test """ moving_body = "moving_body_tracking" moving_body_param = { "eccentricity": 0.0008641, "semimajor_axis": 6801395.04, "inclination": 87.0, "perigee_argument": 10.0, "right_ascension_of_ascending_node": 10.0, "anomaly": 0.0, "anomaly_type": "TRUE", "orbit_update_date":"2021-12-02T00:00:00.000", "frame": "EME"} orbit_params = { "eccentricity": 0.0008641, "semimajor_axis": 6801395.04, "inclination": 87.0, "perigee_argument": 20.0, "right_ascension_of_ascending_node": 10.0, "anomaly": 0.0, "anomaly_type": "TRUE", "orbit_update_date":'2021-12-02T00:00:00.000', "frame": "EME"} orbit_propagator_1 = analytical_propagator(orbit_params) orbit_propagator_2 = analytical_propagator(orbit_params) attitude_m_body = attitude_provider_constructor(moving_body, moving_body_param) attitude_m_body_1 = moving_body_pointing_law(analytical_propagator(moving_body_param),moving_body_param) orbit_propagator_1.setAttitudeProvider(attitude_m_body) orbit_propagator_2.setAttitudeProvider(attitude_m_body_1) time_to_propagate = orekit_utils.absolute_time_converter_utc_string('2022-05-02T00:00:00.000') state_1 = orbit_propagator_1.propagate(time_to_propagate) state_2 = orbit_propagator_2.propagate(time_to_propagate) self.assertTrue((state_1.getAttitude().getSpin().toString() == state_2.getAttitude().getSpin().toString())) ground = "ground_tracking" ground_param = { "latitude": 12.0, "altitude": 2343.0, "longitude":12.0 } parameters = { "eccentricity": 0.0008641, "semimajor_axis": 6801395.04, "inclination": 87.0, "perigee_argument": 10.0, "right_ascension_of_ascending_node": 10.0, "anomaly": radians(0.0), "anomaly_type": "TRUE", "orbit_update_date":'2021-12-02T00:00:00.000', "frame": "EME"} orbit_propagator_1 = analytical_propagator(parameters) orbit_propagator_2 = analytical_propagator(parameters) ground_param["frame"] = orekit_utils.frame_to_string(orbit_propagator_1.getFrame()) attitude_provider_1 = attitude_provider_constructor(ground, ground_param) attitude_provider_2 = ground_pointing_law(ground_param) orbit_propagator_1.setAttitudeProvider(attitude_provider_1) orbit_propagator_2.setAttitudeProvider(attitude_provider_2) time_to_propagate = orekit_utils.absolute_time_converter_utc_string('2022-05-02T00:00:00.000') state_1 = orbit_propagator_1.propagate(time_to_propagate) state_2 = orbit_propagator_2.propagate(time_to_propagate) self.assertTrue((state_1.getAttitude().getSpin().toString() == state_2.getAttitude().getSpin().toString()))
async def test_simulation_timepulse_propagate(self): """ Test the simulation_timepulse_propagate() callback """ # Creating variables that will be used as arguments for the callback logger = FakeLogger() loop = asyncio.get_running_loop() nats = FakeNatsHandler("cubesat_1", "4222", loop=loop, user="******", password="******") await nats.connect() # opening a file that contains a sample shared storage f = open("test_orbits_config.json") shared_storage = json.load(f) # Testing the callback across mulitple timesteps for i in range(10, 59): # creating sample data data = { "sender_ID": "cubesat_2", "time_sent": "2021-12-05T00:" + str(i) + ":00.000", "data": { "time": "2021-12-05T00:" + str(i) + ":00.000" } } orbit_1 = shared_storage["swarm"]["cubesat_1"]["orbit"] orbit_2 = shared_storage["swarm"]["cubesat_2"]["orbit"] attitude_provider_1 = { "type": "moving_body_tracking", "parameters": shared_storage["swarm"][shared_storage["swarm"]["cubesat_1"] ["orbit"]["attitude"]]["orbit"] } attitude_provider_2 = { "type": "moving_body_tracking", "parameters": shared_storage["swarm"][shared_storage["swarm"]["cubesat_2"] ["orbit"]["attitude"]]["orbit"] } message = Message.decode_json(data, MessageSchemas.TIMESTEP_MESSAGE) await orbit_service.simulation_timepulse_propagate( message, nats, shared_storage, logger) time = absolute_time_converter_utc_string(data["data"]["time"]) # Creating propagators and attitude provider from orbit configuration of satellites propagator_1 = orekit_utils.analytical_propagator(orbit_1) propagator_2 = orekit_utils.analytical_propagator(orbit_2) attitude_provider_1 = orekit_utils.attitude_provider_constructor( attitude_provider_1["type"], attitude_provider_1["parameters"]) attitude_provider_2 = orekit_utils.attitude_provider_constructor( attitude_provider_2["type"], attitude_provider_2["parameters"]) # Setting attitude and propagating the orbit propagator_1.setAttitudeProvider(attitude_provider_1) propagator_2.setAttitudeProvider(attitude_provider_2) state_1 = propagator_1.propagate(time) state_2 = propagator_2.propagate(time) # Updating param cubesat_1_param = orekit_utils.get_keplerian_parameters(state_1) cubesat_1_param.update({"attitude": "cubesat_2"}) cubesat_1_param.update({"frame": "EME"}) cubesat_2_param = orekit_utils.get_keplerian_parameters(state_2) cubesat_2_param.update({"attitude": "cubesat_1"}) cubesat_2_param.update({"frame": "EME"}) # Checking to see if simulation_timestep_propagate updated params correctly self.assertTrue(shared_storage["swarm"]["cubesat_1"]["orbit"] == cubesat_1_param) self.assertTrue(shared_storage["swarm"]["cubesat_2"]["orbit"] == cubesat_2_param) self.assertTrue(shared_storage["swarm"]["cubesat_1"]["orbit"] ["attitude"] == "cubesat_2") self.assertTrue(shared_storage["swarm"]["cubesat_2"]["orbit"] ["attitude"] == "cubesat_1") print(shared_storage["swarm"]["cubesat_1"]["target_in_view"]) print(shared_storage["swarm"]["cubesat_2"]["target_in_view"]) # Making sure that phonebook gets updated properly if i <= 48: self.assertTrue(shared_storage["sat_phonebook"]["cubesat_2"]) self.assertTrue( shared_storage["swarm"]["cubesat_2"]["target_in_view"]) else: self.assertFalse(shared_storage["sat_phonebook"]["cubesat_2"]) self.assertFalse( shared_storage["swarm"]["cubesat_2"]["target_in_view"])