|
|
|
@ -1,5 +1,6 @@ |
|
|
|
|
#!/usr/bin/env python3 |
|
|
|
|
import json |
|
|
|
|
import os |
|
|
|
|
import time |
|
|
|
|
from collections import defaultdict |
|
|
|
|
from concurrent.futures import Future, ProcessPoolExecutor |
|
|
|
@ -32,8 +33,10 @@ class Laikad: |
|
|
|
|
save_ephemeris=False, last_known_position=None): |
|
|
|
|
self.astro_dog = AstroDog(valid_const=valid_const, auto_update=auto_update, valid_ephem_types=valid_ephem_types, clear_old_ephemeris=True) |
|
|
|
|
self.gnss_kf = GNSSKalman(GENERATED_DIR) |
|
|
|
|
self.orbit_fetch_executor = ProcessPoolExecutor() |
|
|
|
|
|
|
|
|
|
self.orbit_fetch_executor: Optional[ProcessPoolExecutor] = None |
|
|
|
|
self.orbit_fetch_future: Optional[Future] = None |
|
|
|
|
|
|
|
|
|
self.last_fetch_orbits_t = None |
|
|
|
|
self.last_cached_t = None |
|
|
|
|
self.save_ephemeris = save_ephemeris |
|
|
|
@ -44,9 +47,13 @@ class Laikad: |
|
|
|
|
self.last_pos_fix_t = None |
|
|
|
|
|
|
|
|
|
def load_cache(self): |
|
|
|
|
if not self.save_ephemeris: |
|
|
|
|
return |
|
|
|
|
|
|
|
|
|
cache = Params().get(EPHEMERIS_CACHE) |
|
|
|
|
if not cache: |
|
|
|
|
return |
|
|
|
|
|
|
|
|
|
try: |
|
|
|
|
cache = json.loads(cache, object_hook=deserialize_hook) |
|
|
|
|
self.astro_dog.add_orbits(cache['orbits']) |
|
|
|
@ -71,7 +78,7 @@ class Laikad: |
|
|
|
|
self.last_pos_residual = pos_fix_residual |
|
|
|
|
self.last_pos_fix_t = t |
|
|
|
|
return self.last_pos_fix |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def process_ublox_msg(self, ublox_msg, ublox_mono_time: int, block=False): |
|
|
|
|
if ublox_msg.which == 'measurementReport': |
|
|
|
|
t = ublox_mono_time * 1e-9 |
|
|
|
@ -152,17 +159,22 @@ class Laikad: |
|
|
|
|
def fetch_orbits(self, t: GPSTime, block): |
|
|
|
|
if t not in self.astro_dog.orbit_fetched_times and (self.last_fetch_orbits_t is None or t - self.last_fetch_orbits_t > SECS_IN_HR): |
|
|
|
|
astro_dog_vars = self.astro_dog.valid_const, self.astro_dog.auto_update, self.astro_dog.valid_ephem_types |
|
|
|
|
if self.orbit_fetch_future is None: |
|
|
|
|
|
|
|
|
|
ret = None |
|
|
|
|
|
|
|
|
|
if block: |
|
|
|
|
ret = get_orbit_data(t, *astro_dog_vars) |
|
|
|
|
elif self.orbit_fetch_future is None: |
|
|
|
|
self.orbit_fetch_executor = ProcessPoolExecutor(max_workers=1) |
|
|
|
|
self.orbit_fetch_future = self.orbit_fetch_executor.submit(get_orbit_data, t, *astro_dog_vars) |
|
|
|
|
if block: |
|
|
|
|
self.orbit_fetch_future.result() |
|
|
|
|
if self.orbit_fetch_future.done(): |
|
|
|
|
ret = self.orbit_fetch_future.result() |
|
|
|
|
elif self.orbit_fetch_future.done(): |
|
|
|
|
self.last_fetch_orbits_t = t |
|
|
|
|
if ret: |
|
|
|
|
self.astro_dog.orbits, self.astro_dog.orbit_fetched_times = ret |
|
|
|
|
self.cache_ephemeris(t=t) |
|
|
|
|
self.orbit_fetch_future = None |
|
|
|
|
ret = self.orbit_fetch_future.result() |
|
|
|
|
self.orbit_fetch_executor = self.orbit_fetch_future = None |
|
|
|
|
|
|
|
|
|
if ret is not None: |
|
|
|
|
self.astro_dog.orbits, self.astro_dog.orbit_fetched_times = ret |
|
|
|
|
self.cache_ephemeris(t=t) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_orbit_data(t: GPSTime, valid_const, auto_update, valid_ephem_types): |
|
|
|
@ -174,7 +186,7 @@ def get_orbit_data(t: GPSTime, valid_const, auto_update, valid_ephem_types): |
|
|
|
|
astro_dog.get_orbit_data(t, only_predictions=True) |
|
|
|
|
data = (astro_dog.orbits, astro_dog.orbit_fetched_times) |
|
|
|
|
except RuntimeError as e: |
|
|
|
|
cloudlog.info(f"No orbit data found. {e}") |
|
|
|
|
cloudlog.warning(f"No orbit data found. {e}") |
|
|
|
|
cloudlog.info(f"Done parsing orbits. Took {time.monotonic() - start_time:.1f}s") |
|
|
|
|
return data |
|
|
|
|
|
|
|
|
@ -255,17 +267,21 @@ class EphemerisSourceType(IntEnum): |
|
|
|
|
glonassIacUltraRapid = 2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main(): |
|
|
|
|
sm = messaging.SubMaster(['ubloxGnss']) |
|
|
|
|
pm = messaging.PubMaster(['gnssMeasurements']) |
|
|
|
|
def main(sm=None, pm=None): |
|
|
|
|
if sm is None: |
|
|
|
|
sm = messaging.SubMaster(['ubloxGnss']) |
|
|
|
|
if pm is None: |
|
|
|
|
pm = messaging.PubMaster(['gnssMeasurements']) |
|
|
|
|
|
|
|
|
|
replay = "REPLAY" in os.environ |
|
|
|
|
# todo get last_known_position |
|
|
|
|
laikad = Laikad(save_ephemeris=True) |
|
|
|
|
laikad = Laikad(save_ephemeris=not replay) |
|
|
|
|
while True: |
|
|
|
|
sm.update() |
|
|
|
|
|
|
|
|
|
if sm.updated['ubloxGnss']: |
|
|
|
|
ublox_msg = sm['ubloxGnss'] |
|
|
|
|
msg = laikad.process_ublox_msg(ublox_msg, sm.logMonoTime['ubloxGnss']) |
|
|
|
|
msg = laikad.process_ublox_msg(ublox_msg, sm.logMonoTime['ubloxGnss'], block=replay) |
|
|
|
|
if msg is not None: |
|
|
|
|
pm.send('gnssMeasurements', msg) |
|
|
|
|
|
|
|
|
|