From d58bae0464f79c2568beccf4f52690dde8331dbd Mon Sep 17 00:00:00 2001 From: Caileigh Fitzgerald <cfitzgerald@whoi.edu> Date: Tue, 28 May 2024 18:46:55 +0000 Subject: [PATCH 1/4] fixed bug in logic for depth. Depths should be positive --- ros_acomms_modeling/src/sim_transmission_loss_node.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ros_acomms_modeling/src/sim_transmission_loss_node.py b/ros_acomms_modeling/src/sim_transmission_loss_node.py index 81ae11f9..b74b39ce 100755 --- a/ros_acomms_modeling/src/sim_transmission_loss_node.py +++ b/ros_acomms_modeling/src/sim_transmission_loss_node.py @@ -215,12 +215,12 @@ class SimTransmissionLossNode(object): rospy.logerr(f"Receiver depth ({dest_depth}) is greater than water depth ({self.water_depth}). Can't calculate receive level; returning 0dB") return 0 - if src_depth >= 0: - rospy.logwarn(f"Source depth is 0; setting it to 0.1 to calculate receive level") + if src_depth <= 0: + rospy.logwarn(f"Source depth <= 0; setting it to 0.1 to calculate receive level") src_depth = 0.1 - if dest_depth >= 0: - rospy.logwarn(f"Receiver depth is 0; setting it to 0.1 to calculate receive level") + if dest_depth <= 0: + rospy.logwarn(f"Receiver depth <= 0; setting it to 0.1 to calculate receive level") dest_depth = 0.1 return self.get_receive_level_bellhop(horizontal_range, src_depth, dest_depth, -- GitLab From d85d0fc937be5cb5f8129703775b96ebefc9f36f Mon Sep 17 00:00:00 2001 From: Caileigh Fitzgerald <cfitzgerald@whoi.edu> Date: Tue, 28 May 2024 18:48:57 +0000 Subject: [PATCH 2/4] removed distance_haversine calculation in favor of geopy method used in sim_tramission_loss. Added class attr for checking if we are using sim_time --- ros_acomms_modeling/src/modem_sim_node.py | 55 +++++++++++------------ 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/ros_acomms_modeling/src/modem_sim_node.py b/ros_acomms_modeling/src/modem_sim_node.py index ed262fb7..0c0c6145 100755 --- a/ros_acomms_modeling/src/modem_sim_node.py +++ b/ros_acomms_modeling/src/modem_sim_node.py @@ -12,7 +12,7 @@ from queue import Queue, Empty, Full from threading import Thread, Event from collections import namedtuple, deque import datetime -import math +from geopy.distance import distance as geopy_distance import numpy as np from typing import Optional, List # Use ros_groundtruth messages for sim if available, otherwise use internal versions. @@ -36,27 +36,6 @@ def deserialze_anymsg(msg_data: AnyMsg): msg.deserialize(msg_data._buff) return msg -def distance_haversine(lat1, lon1, lat2, lon2, meters=False): - # approximate radius of earth in km - R = 6373.0 * 1000 - - lat1 = math.radians(lat1) - lon1 = math.radians(lon1) - lat2 = math.radians(lat2) - lon2 = math.radians(lon2) - - dlon = lon2 - lon1 - dlat = lat2 - lat1 - - a = math.sin(dlat / 2) ** 2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon / 2) ** 2 - c = 2 * math.atan2( math.sqrt(a), math.sqrt(1 - a)) - - distance = R * c - - if meters: - return distance - return distance / 1000 - class PingReplyTransaction(object): PING_TYPE_NONE = 0 PING_TYPE_REQUEST = 1 @@ -168,6 +147,14 @@ class ModemSimNode(object): else: self.tock_topic_name = 'tock' + use_sim_time_name = rospy.search_param('use_sim_time') + if use_sim_time_name: + self.use_sim_time = rospy.get_param( + use_sim_time_name, default=False) + else: + self.use_sim_time = False + rospy.loginfo("use_sim_time {} ".format(self.use_sim_time)) + location_source_param = rospy.get_param('~modem_location_source', default=None) if location_source_param: rospy.logwarn("modem_location_source and the GetPlatformLocation service is no longer supported. " + @@ -568,22 +555,30 @@ class ModemSimNode(object): recv_level = transmission_loss.rcv_rx_level_db # receive source level arrival_time = transmission_loss.transmission_delay + sim_packet.transmit_time finish_time = arrival_time + sim_packet.transmit_duration - arrival_time_str = str(datetime.datetime.fromtimestamp(arrival_time.to_sec())) + arrival_time_str = str(datetime.datetime.utcfromtimestamp(arrival_time.to_sec())) + src = (sim_packet.src_latitude, sim_packet.src_longitude) + rcv = (rcv_platform_location.latitude, rcv_platform_location.longitude) rospy.loginfo( - "MODEM %d: T2: Receive level: %f Arrival time: %s", - self.src, recv_level, arrival_time_str + "MODEM %d: T2: Receive level: %s Arrival time: %s SRC: (%s) RCV: (%s)", + self.src, f'{recv_level:.2f}', arrival_time_str, + f'{src[0]:.2f}, {src[1]:.2f}, {sim_packet.src_depth:.2f}', + f'{rcv[0]:.2f}, {rcv[1]:.2f}, {rcv_platform_location.depth:.2f}' ) try: owtt = (arrival_time - sim_packet.transmit_time).to_sec() - distance = distance_haversine(sim_packet.src_latitude, sim_packet.src_longitude, rcv_platform_location.latitude, rcv_platform_location.longitude) - sound_speed = (distance * 1000) / owtt + if owtt <= 0: + rospy.logwarn(f'WARNING: reception with OWTT <= 0! owtt: {owtt}. Setting to 0.00066 for range calc.. (1m @ 1500m/s)') + owtt = 0.00066 + distance_m = geopy_distance(src, rcv, ellipsoid='WGS-84').meters + sound_speed = distance_m / owtt rospy.loginfo( - "MODEM %d: T2: SRC lat/lon: %f, %f RCV lat/lon: %f, %f Distance (km): %s OWTT: %s Sound Speed (m/s): %s", - self.src, sim_packet.src_latitude, sim_packet.src_longitude, rcv_platform_location.latitude, rcv_platform_location.longitude, - f'{distance:.2f}', f'{owtt:.2f}', f'{sound_speed:.2f}', + "MODEM %d: T2: Distance (km): %s, OWTT: %s Sound Speed (m/s): %s", + self.src, f'{distance_m / 1000:.2f}', f'{owtt:.2f}', f'{sound_speed:.2f}', ) except: + # TODO: we don't want to spam the user with warnings but, we need to handle the case where location params are, + # .. out of range/invalid. we handle owtt <= 0 but, other cases should potentially be handled here. pass return recv_level, arrival_time, finish_time -- GitLab From 2978cf95938cd526d41eaed7a6efb1d91f90dc17 Mon Sep 17 00:00:00 2001 From: Caileigh Fitzgerald <cfitzgerald@whoi.edu> Date: Tue, 28 May 2024 18:49:54 +0000 Subject: [PATCH 3/4] updates to modem_location_sim simple_path. Default mode unchanged. code cleaned up --- .../src/modem_location_sim_node.py | 37 ++++++++++++++----- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/ros_acomms_modeling/src/modem_location_sim_node.py b/ros_acomms_modeling/src/modem_location_sim_node.py index 77a107b1..d9aacb41 100755 --- a/ros_acomms_modeling/src/modem_location_sim_node.py +++ b/ros_acomms_modeling/src/modem_location_sim_node.py @@ -15,36 +15,53 @@ class ModemLocationSimNode: self.simple_path = rospy.get_param('simple_path', False) self.random_seed = rospy.get_param('random_seed', None) - self._start_lat = 41553703 - self._start_lon = 70843443 - self.offset = 1000 + self.min_depth = rospy.get_param('min_depth', 3) + self.max_depth = rospy.get_param('max_depth', 18) + self.offset = rospy.get_param('simple_path_offset', 10) + + self._start_lat = 41421580 + self._start_lon = 70726027 + self._end_lat = 41553703 + self._end_lon = 70843443 + self.rng = default_rng(self.random_seed) self.location_publisher = rospy.Publisher('location', Location, latch=True, queue_size=10) + + published_origin = False while not rospy.is_shutdown(): if self.simple_path: - start_lat, start_lon = self.next_start_lat_lon() + if published_origin: + start_lat, start_lon = self.next_start_lat_lon() + else: + start_lat, start_lon = self._start_lat, self.start_lon + published_origin = True self.pub_path_location(start_lat, start_lon) else: self.pub_location() rospy.sleep(update_period) + def next_depth(self): + if self.min_depth > self.max_depth: + return self.rng.uniform(self.max_depth, self.min_depth) + return self.rng.uniform(self.min_depth, self.max_depth) + def next_start_lat_lon(self): - self._start_lat += self.rng.uniform(-10, 10) - self._start_lon += self.rng.uniform(-10, 10) + self._start_lat += self.rng.uniform(-5, 5) + self._start_lon += self.rng.uniform(-5, 5) return self._start_lat, self._start_lon def pub_path_location(self, start_lat, start_lon): lat = self.rng.uniform(start_lat, start_lat + self.offset) * (10 ** -6) lon = self.rng.uniform(start_lon, start_lon + self.offset) * -(10 ** -6) - depth = self.rng.uniform(3, 18) + depth = self.next_depth() msg = Location(header=Header(stamp=rospy.get_rostime()), latitude=lat, longitude=lon, depth=depth) self.location_publisher.publish(msg) def pub_location(self): - lat = self.rng.uniform(41421580, 41553703) * (10 ** -6) - lon = self.rng.uniform(70726027, 70843443) * -(10 ** -6) - depth = self.rng.uniform(3, 18) + lat = self.rng.uniform(self._start_lat, self._end_lat) * (10 ** -6) + lon = self.rng.uniform(self._start_lon, self._end_lon) * -(10 ** -6) + depth = self.next_depth() msg = Location(header=Header(stamp=rospy.get_rostime()), latitude=lat, longitude=lon, depth=depth) self.location_publisher.publish(msg) -- GitLab From 6eb2838ac92af96e0f5ca4500e1566370364fb24 Mon Sep 17 00:00:00 2001 From: Caileigh Fitzgerald <cfitzgerald@whoi.edu> Date: Tue, 28 May 2024 18:52:41 +0000 Subject: [PATCH 4/4] added non-default rosparam ~start_sim_at_current_time. clock generator now has an option to start the sim clock relative to the starting time. Otherwise, default behavior starts sim clock at 0.0 --- ros_acomms_modeling/src/clock_generator.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/ros_acomms_modeling/src/clock_generator.py b/ros_acomms_modeling/src/clock_generator.py index 8cf554ab..3e26e746 100755 --- a/ros_acomms_modeling/src/clock_generator.py +++ b/ros_acomms_modeling/src/clock_generator.py @@ -9,6 +9,7 @@ This script contains the clock_generator class which publishes a clock message a import rospy from rosgraph_msgs.msg import Clock import time +import datetime class ClockGenerator: """ @@ -22,8 +23,17 @@ class ClockGenerator: clock_publisher = rospy.Publisher('clock', Clock, queue_size=10) rate = rospy.get_param("~publish_rate", 50) sim_speed_multiplier = rospy.get_param("~multiplier", 5) + start_sim_at_current_time = rospy.get_param("~start_sim_at_current_time", False) sim_clock_msg = Clock() - current_time = rospy.get_time() + + if not start_sim_at_current_time: + # starts the sim from 0.0 (rospy.get_time() returns 0.0 before msg is published on /clock) + current_time = rospy.get_time() + else: + # rather than start the sim from 0, we can start it relative to launch + current_time = datetime.datetime.now().timestamp() + sim_clock_msg.clock = rospy.Time.from_sec(current_time) + clock_publisher.publish(sim_clock_msg) while not rospy.is_shutdown(): current_time += (1 / rate) * sim_speed_multiplier -- GitLab