Improve GPS tests, add qcom tests (#26060)
* first ignore
* init gps test
* make LimeGPS git clone
* gps test v1
* add static signal gen script
* remove LD_PRELOAD by using rpath, update values after testing
* cleanUp
* update fuzzy tests
* finalize qcom gps tests
* add downloader
* finalize unit tests
* inc limeGPS startup time
* loosen init time
* add ublox warmstart test
* improve location tests
Co-authored-by: Kurt Nistelberger <kurt.nistelberger@gmail.com>
old-commit-hash: 9c92814585
taco
parent
5b90a8ce15
commit
9c791ad9b2
7 changed files with 327 additions and 121 deletions
@ -1,83 +0,0 @@ |
||||
#!/usr/bin/env python3 |
||||
import os |
||||
import sys |
||||
import random |
||||
import datetime as dt |
||||
import subprocess as sp |
||||
from typing import Tuple |
||||
|
||||
from laika.downloader import download_nav |
||||
from laika.gps_time import GPSTime |
||||
from laika.helpers import ConstellationId |
||||
|
||||
cache_dir = '/tmp/gpstest/' |
||||
|
||||
|
||||
def download_rinex(): |
||||
# TODO: check if there is a better way to get the full brdc file for LimeGPS |
||||
gps_time = GPSTime.from_datetime(dt.datetime.utcnow()) |
||||
utc_time = dt.datetime.utcnow() - dt.timedelta(1) |
||||
gps_time = GPSTime.from_datetime(dt.datetime(utc_time.year, utc_time.month, utc_time.day)) |
||||
return download_nav(gps_time, cache_dir, ConstellationId.GPS) |
||||
|
||||
|
||||
def get_random_coords(lat, lon) -> Tuple[int, int]: |
||||
# jump around the world |
||||
# max values, lat: -90 to 90, lon: -180 to 180 |
||||
|
||||
lat_add = random.random()*20 + 10 |
||||
lon_add = random.random()*20 + 20 |
||||
|
||||
lat = ((lat + lat_add + 90) % 180) - 90 |
||||
lon = ((lon + lon_add + 180) % 360) - 180 |
||||
return round(lat, 5), round(lon, 5) |
||||
|
||||
|
||||
def check_availability() -> bool: |
||||
cmd = ["LimeSuite/builddir/LimeUtil/LimeUtil", "--find"] |
||||
output = sp.check_output(cmd) |
||||
|
||||
if output.strip() == b"": |
||||
return False |
||||
|
||||
print(f"Device: {output.strip().decode('utf-8')}") |
||||
return True |
||||
|
||||
|
||||
def main(): |
||||
if not os.path.exists('LimeGPS'): |
||||
print("LimeGPS not found run 'setup.sh' first") |
||||
return |
||||
|
||||
if not os.path.exists('LimeSuite'): |
||||
print("LimeSuite not found run 'setup.sh' first") |
||||
return |
||||
|
||||
if not check_availability(): |
||||
print("No limeSDR device found!") |
||||
return |
||||
|
||||
rinex_file = download_rinex() |
||||
lat, lon = get_random_coords(47.2020, 15.7403) |
||||
|
||||
if len(sys.argv) == 3: |
||||
lat = float(sys.argv[1]) |
||||
lon = float(sys.argv[2]) |
||||
|
||||
try: |
||||
print(f"starting LimeGPS, Location: {lat},{lon}") |
||||
cmd = ["LimeGPS/LimeGPS", "-e", rinex_file, "-l", f"{lat},{lon},100"] |
||||
sp.check_output(cmd, stderr=sp.PIPE) |
||||
except KeyboardInterrupt: |
||||
print("stopping LimeGPS") |
||||
except Exception as e: |
||||
out_stderr = e.stderr.decode('utf-8')# pylint:disable=no-member |
||||
if "Device is busy." in out_stderr: |
||||
print("GPS simulation is already running, Device is busy!") |
||||
return |
||||
|
||||
print(f"LimeGPS crashed: {str(e)}") |
||||
print(f"stderr:\n{e.stderr.decode('utf-8')}")# pylint:disable=no-member |
||||
|
||||
if __name__ == "__main__": |
||||
main() |
@ -0,0 +1,16 @@ |
||||
#!/bin/bash |
||||
|
||||
# NOTE: can only run inside limeGPS test box! |
||||
|
||||
# run limeGPS with random static location |
||||
timeout 300 ./simulate_gps_signal.py & |
||||
gps_PID=$? |
||||
|
||||
echo "starting limeGPS..." |
||||
sleep 10 |
||||
|
||||
# run unit tests (skipped when module not present) |
||||
python -m unittest test_gps.py |
||||
python -m unittest test_gps_qcom.py |
||||
|
||||
kill $gps_PID |
@ -0,0 +1,102 @@ |
||||
#!/usr/bin/env python3 |
||||
import os |
||||
import random |
||||
import argparse |
||||
import datetime as dt |
||||
import subprocess as sp |
||||
from typing import Tuple |
||||
|
||||
from laika.downloader import download_nav |
||||
from laika.gps_time import GPSTime |
||||
from laika.helpers import ConstellationId |
||||
|
||||
cache_dir = '/tmp/gpstest/' |
||||
|
||||
|
||||
def download_rinex(): |
||||
# TODO: check if there is a better way to get the full brdc file for LimeGPS |
||||
gps_time = GPSTime.from_datetime(dt.datetime.utcnow()) |
||||
utc_time = dt.datetime.utcnow() - dt.timedelta(1) |
||||
gps_time = GPSTime.from_datetime(dt.datetime(utc_time.year, utc_time.month, utc_time.day)) |
||||
return download_nav(gps_time, cache_dir, ConstellationId.GPS) |
||||
|
||||
def get_coords(lat, lon, s1, s2, o1=0, o2=0) -> Tuple[int, int]: |
||||
lat_add = random.random()*s1 + o1 |
||||
lon_add = random.random()*s2 + o2 |
||||
|
||||
lat = ((lat + lat_add + 90) % 180) - 90 |
||||
lon = ((lon + lon_add + 180) % 360) - 180 |
||||
return round(lat, 5), round(lon, 5) |
||||
|
||||
def get_continuous_coords(lat, lon) -> Tuple[int, int]: |
||||
# continuously move around the world |
||||
return get_coords(lat, lon, 0.01, 0.01) |
||||
|
||||
def get_random_coords(lat, lon) -> Tuple[int, int]: |
||||
# jump around the world |
||||
return get_coords(lat, lon, 20, 20, 10, 20) |
||||
|
||||
def check_availability() -> bool: |
||||
cmd = ["LimeSuite/builddir/LimeUtil/LimeUtil", "--find"] |
||||
output = sp.check_output(cmd) |
||||
|
||||
if output.strip() == b"": |
||||
return False |
||||
|
||||
print(f"Device: {output.strip().decode('utf-8')}") |
||||
return True |
||||
|
||||
def main(lat, lon, jump_sim, contin_sim): |
||||
if not os.path.exists('LimeGPS'): |
||||
print("LimeGPS not found run 'setup.sh' first") |
||||
return |
||||
|
||||
if not os.path.exists('LimeSuite'): |
||||
print("LimeSuite not found run 'setup.sh' first") |
||||
return |
||||
|
||||
if not check_availability(): |
||||
print("No limeSDR device found!") |
||||
return |
||||
|
||||
rinex_file = download_rinex() |
||||
|
||||
if lat == 0 and lon == 0: |
||||
lat, lon = get_random_coords(47.2020, 15.7403) |
||||
|
||||
timeout = None |
||||
if jump_sim: |
||||
timeout = 30 |
||||
|
||||
while True: |
||||
try: |
||||
print(f"starting LimeGPS, Location: {lat},{lon}") |
||||
cmd = ["LimeGPS/LimeGPS", "-e", rinex_file, "-l", f"{lat},{lon},100"] |
||||
sp.check_output(cmd, stderr=sp.PIPE, timeout=timeout) |
||||
except KeyboardInterrupt: |
||||
print("stopping LimeGPS") |
||||
return |
||||
except sp.TimeoutExpired: |
||||
print("LimeGPS timeout reached!") |
||||
except Exception as e: |
||||
out_stderr = e.stderr.decode('utf-8')# pylint:disable=no-member |
||||
if "Device is busy." in out_stderr: |
||||
print("GPS simulation is already running, Device is busy!") |
||||
return |
||||
|
||||
print(f"LimeGPS crashed: {str(e)}") |
||||
print(f"stderr:\n{e.stderr.decode('utf-8')}")# pylint:disable=no-member |
||||
|
||||
if contin_sim: |
||||
lat, lon = get_continuous_coords(lat, lon) |
||||
else: |
||||
lat, lon = get_random_coords(lat, lon) |
||||
|
||||
if __name__ == "__main__": |
||||
parser = argparse.ArgumentParser(description="Simulate static [or random jumping] GPS signal.") |
||||
parser.add_argument("lat", type=float, nargs='?', default=0) |
||||
parser.add_argument("lon", type=float, nargs='?', default=0) |
||||
parser.add_argument("--jump", action="store_true", help="signal that jumps around the world") |
||||
parser.add_argument("--contin", action="store_true", help="continuously/slowly moving around the world") |
||||
args = parser.parse_args() |
||||
main(args.lat, args.lon, args.jump, args.contin) |
@ -0,0 +1,109 @@ |
||||
#!/usr/bin/env python3 |
||||
import time |
||||
import unittest |
||||
import subprocess as sp |
||||
|
||||
from common.params import Params |
||||
from system.hardware import TICI |
||||
import cereal.messaging as messaging |
||||
from selfdrive.manager.process_config import managed_processes |
||||
|
||||
|
||||
def exec_mmcli(cmd): |
||||
cmd = "mmcli -m 0 " + cmd |
||||
p = sp.Popen(cmd, shell=True, stdout=sp.PIPE, stderr=sp.PIPE) |
||||
return p.communicate() |
||||
|
||||
|
||||
def wait_for_location(socket, timeout): |
||||
while True: |
||||
events = messaging.drain_sock(socket) |
||||
for event in events: |
||||
if event.gpsLocation.flags % 2: |
||||
return False |
||||
|
||||
timeout -= 1 |
||||
if timeout <= 0: |
||||
return True |
||||
|
||||
time.sleep(0.1) |
||||
continue |
||||
|
||||
|
||||
class TestGPS(unittest.TestCase): |
||||
@classmethod |
||||
def setUpClass(cls): |
||||
if not TICI: |
||||
raise unittest.SkipTest |
||||
|
||||
ublox_available = Params().get_bool("UbloxAvailable") |
||||
if ublox_available: |
||||
raise unittest.SkipTest |
||||
|
||||
@unittest.skip("Skip cold start test due to time") |
||||
def test_quectel_cold_start(self): |
||||
# delete assistance data to enforce cold start for GNSS |
||||
# testing shows that this takes up to 20min |
||||
|
||||
# invalidate supl setting, cannot be reset |
||||
_, err = exec_mmcli("--location-set-supl-server=unittest:1") |
||||
|
||||
_, err = exec_mmcli("--command='AT+QGPSDEL=0'") |
||||
assert len(err) == 0, f"GPSDEL failed: {err}" |
||||
|
||||
managed_processes['rawgpsd'].start() |
||||
start_time = time.monotonic() |
||||
glo = messaging.sub_sock("gpsLocation", timeout=0.1) |
||||
|
||||
timeout = 10*60*25 # 25 minute |
||||
timedout = wait_for_location(glo, timeout) |
||||
managed_processes['rawgpsd'].stop() |
||||
|
||||
assert timedout is False, "Waiting for location timed out (25min)!" |
||||
|
||||
duration = time.monotonic() - start_time |
||||
assert duration < 50, f"Received GPS location {duration}!" |
||||
|
||||
|
||||
def test_a_quectel_cold_start_AGPS(self): |
||||
_, err = exec_mmcli("--command='AT+QGPSDEL=0'") |
||||
assert len(err) == 0, f"GPSDEL failed: {err}" |
||||
|
||||
# setup AGPS |
||||
exec_mmcli("--location-set-supl-server=supl.google.com:7276") |
||||
|
||||
managed_processes['rawgpsd'].start() |
||||
start_time = time.monotonic() |
||||
glo = messaging.sub_sock("gpsLocation", timeout=0.1) |
||||
|
||||
timeout = 10*60*3 # 3 minute |
||||
timedout = wait_for_location(glo, timeout) |
||||
managed_processes['rawgpsd'].stop() |
||||
|
||||
assert timedout is False, "Waiting for location timed out (3min)!" |
||||
|
||||
duration = time.monotonic() - start_time |
||||
assert duration < 60, f"Received GPS location {duration}!" |
||||
|
||||
|
||||
def test_b_quectel_startup(self): |
||||
|
||||
# setup AGPS |
||||
exec_mmcli("--location-set-supl-server=supl.google.com:7276") |
||||
|
||||
managed_processes['rawgpsd'].start() |
||||
start_time = time.monotonic() |
||||
glo = messaging.sub_sock("gpsLocation", timeout=0.1) |
||||
|
||||
timeout = 10*60*3 # 3 minute |
||||
timedout = wait_for_location(glo, timeout) |
||||
managed_processes['rawgpsd'].stop() |
||||
|
||||
assert timedout is False, "Waiting for location timed out (3min)!" |
||||
|
||||
duration = time.monotonic() - start_time |
||||
assert duration < 60, f"Received GPS location {duration}!" |
||||
|
||||
|
||||
if __name__ == "__main__": |
||||
unittest.main() |
Loading…
Reference in new issue