Rm more laika references (#30451)
Rm more laikad references old-commit-hash: 95c6d5140aee76e6fd28990b0b58e1a3dcc5ee62
This commit is contained in:
@@ -1,66 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import cereal.messaging as messaging
|
||||
from laika import constants
|
||||
|
||||
if __name__ == "__main__":
|
||||
sm = messaging.SubMaster(['ubloxGnss', 'qcomGnss'])
|
||||
|
||||
meas = None
|
||||
while 1:
|
||||
sm.update()
|
||||
if sm['ubloxGnss'].which() == "measurementReport":
|
||||
meas = sm['ubloxGnss'].measurementReport.measurements
|
||||
if not sm.updated['qcomGnss'] or meas is None:
|
||||
continue
|
||||
report = sm['qcomGnss'].measurementReport
|
||||
if report.source not in [0, 1]:
|
||||
continue
|
||||
GLONASS = report.source == 1
|
||||
recv_time = report.milliseconds / 1000
|
||||
|
||||
car = []
|
||||
print("qcom has ", sorted([x.svId for x in report.sv]))
|
||||
print("ublox has", sorted([x.svId for x in meas if x.gnssId == (6 if GLONASS else 0)]))
|
||||
for i in report.sv:
|
||||
# match to ublox
|
||||
tm = None
|
||||
for m in meas:
|
||||
if i.svId == m.svId and m.gnssId == 0 and m.sigId == 0 and not GLONASS:
|
||||
tm = m
|
||||
if (i.svId-64) == m.svId and m.gnssId == 6 and m.sigId == 0 and GLONASS:
|
||||
tm = m
|
||||
if tm is None:
|
||||
continue
|
||||
|
||||
if not i.measurementStatus.measurementNotUsable and i.measurementStatus.satelliteTimeIsKnown:
|
||||
sat_time = (i.unfilteredMeasurementIntegral + i.unfilteredMeasurementFraction + i.latency) / 1000
|
||||
ublox_psuedorange = tm.pseudorange
|
||||
qcom_psuedorange = (recv_time - sat_time)*constants.SPEED_OF_LIGHT
|
||||
if GLONASS:
|
||||
glonass_freq = tm.glonassFrequencyIndex - 7
|
||||
ublox_speed = -(constants.SPEED_OF_LIGHT / (constants.GLONASS_L1 + glonass_freq*constants.GLONASS_L1_DELTA)) * (tm.doppler)
|
||||
else:
|
||||
ublox_speed = -(constants.SPEED_OF_LIGHT / constants.GPS_L1) * tm.doppler
|
||||
qcom_speed = i.unfilteredSpeed
|
||||
car.append((i.svId, tm.pseudorange, ublox_speed, qcom_psuedorange, qcom_speed, tm.cno))
|
||||
|
||||
if len(car) == 0:
|
||||
print("nothing to compare")
|
||||
continue
|
||||
|
||||
pr_err, speed_err = 0., 0.
|
||||
for c in car:
|
||||
ublox_psuedorange, ublox_speed, qcom_psuedorange, qcom_speed = c[1:5]
|
||||
pr_err += ublox_psuedorange - qcom_psuedorange
|
||||
speed_err += ublox_speed - qcom_speed
|
||||
pr_err /= len(car)
|
||||
speed_err /= len(car)
|
||||
print("avg psuedorange err %f avg speed err %f" % (pr_err, speed_err))
|
||||
for c in sorted(car, key=lambda x: abs(x[1] - x[3] - pr_err)):
|
||||
svid, ublox_psuedorange, ublox_speed, qcom_psuedorange, qcom_speed, cno = c
|
||||
print("svid: %3d pseudorange: %10.2f m speed: %8.2f m/s meas: %12.2f speed: %10.2f meas_err: %10.3f speed_err: %8.3f cno: %d" %
|
||||
(svid, ublox_psuedorange, ublox_speed, qcom_psuedorange, qcom_speed,
|
||||
ublox_psuedorange - qcom_psuedorange - pr_err, ublox_speed - qcom_speed - speed_err, cno))
|
||||
|
||||
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import unittest
|
||||
import time
|
||||
import numpy as np
|
||||
|
||||
from laika import AstroDog
|
||||
from laika.helpers import ConstellationId
|
||||
from laika.raw_gnss import correct_measurements, process_measurements, read_raw_ublox
|
||||
from laika.opt import calc_pos_fix
|
||||
from openpilot.selfdrive.test.openpilotci import get_url
|
||||
from openpilot.system.hardware.hw import Paths
|
||||
from openpilot.tools.lib.logreader import LogReader
|
||||
from openpilot.selfdrive.test.helpers import with_processes
|
||||
import cereal.messaging as messaging
|
||||
|
||||
def get_gnss_measurements(log_reader):
|
||||
gnss_measurements = []
|
||||
for msg in log_reader:
|
||||
if msg.which() == "ubloxGnss":
|
||||
ublox_msg = msg.ubloxGnss
|
||||
if ublox_msg.which == 'measurementReport':
|
||||
report = ublox_msg.measurementReport
|
||||
if len(report.measurements) > 0:
|
||||
gnss_measurements.append(read_raw_ublox(report))
|
||||
return gnss_measurements
|
||||
|
||||
def get_ublox_raw(log_reader):
|
||||
ublox_raw = []
|
||||
for msg in log_reader:
|
||||
if msg.which() == "ubloxRaw":
|
||||
ublox_raw.append(msg)
|
||||
return ublox_raw
|
||||
|
||||
class TestUbloxProcessing(unittest.TestCase):
|
||||
NUM_TEST_PROCESS_MEAS = 10
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
lr = LogReader(get_url("4cf7a6ad03080c90|2021-09-29--13-46-36", 0))
|
||||
cls.gnss_measurements = get_gnss_measurements(lr)
|
||||
|
||||
# test gps ephemeris continuity check (drive has ephemeris issues with cutover data)
|
||||
lr = LogReader(get_url("37b6542f3211019a|2023-01-15--23-45-10", 14))
|
||||
cls.ublox_raw = get_ublox_raw(lr)
|
||||
|
||||
def test_read_ublox_raw(self):
|
||||
count_gps = 0
|
||||
count_glonass = 0
|
||||
for measurements in self.gnss_measurements:
|
||||
for m in measurements:
|
||||
if m.constellation_id == ConstellationId.GPS:
|
||||
count_gps += 1
|
||||
elif m.constellation_id == ConstellationId.GLONASS:
|
||||
count_glonass += 1
|
||||
|
||||
self.assertEqual(count_gps, 5036)
|
||||
self.assertEqual(count_glonass, 3651)
|
||||
|
||||
def test_get_fix(self):
|
||||
dog = AstroDog(cache_dir=Paths.download_cache_root())
|
||||
position_fix_found = 0
|
||||
count_processed_measurements = 0
|
||||
count_corrected_measurements = 0
|
||||
position_fix_found_after_correcting = 0
|
||||
|
||||
pos_ests = []
|
||||
for measurements in self.gnss_measurements[:self.NUM_TEST_PROCESS_MEAS]:
|
||||
processed_meas = process_measurements(measurements, dog)
|
||||
count_processed_measurements += len(processed_meas)
|
||||
pos_fix = calc_pos_fix(processed_meas)
|
||||
if len(pos_fix) > 0 and all(p != 0 for p in pos_fix[0]):
|
||||
position_fix_found += 1
|
||||
|
||||
corrected_meas = correct_measurements(processed_meas, pos_fix[0][:3], dog)
|
||||
count_corrected_measurements += len(corrected_meas)
|
||||
|
||||
pos_fix = calc_pos_fix(corrected_meas)
|
||||
if len(pos_fix) > 0 and all(p != 0 for p in pos_fix[0]):
|
||||
pos_ests.append(pos_fix[0])
|
||||
position_fix_found_after_correcting += 1
|
||||
|
||||
mean_fix = np.mean(np.array(pos_ests)[:, :3], axis=0)
|
||||
np.testing.assert_allclose(mean_fix, [-2452306.662377, -4778343.136806, 3428550.090557], rtol=0, atol=1)
|
||||
|
||||
# Note that can happen that there are less corrected measurements compared to processed when they are invalid.
|
||||
# However, not for the current segment
|
||||
self.assertEqual(position_fix_found, self.NUM_TEST_PROCESS_MEAS)
|
||||
self.assertEqual(position_fix_found_after_correcting, self.NUM_TEST_PROCESS_MEAS)
|
||||
self.assertEqual(count_processed_measurements, 69)
|
||||
self.assertEqual(count_corrected_measurements, 69)
|
||||
|
||||
@with_processes(['ubloxd'])
|
||||
def test_ublox_gps_cutover(self):
|
||||
time.sleep(2)
|
||||
ugs = messaging.sub_sock("ubloxGnss", timeout=0.1)
|
||||
ur_pm = messaging.PubMaster(['ubloxRaw'])
|
||||
|
||||
def replay_segment():
|
||||
rcv_msgs = []
|
||||
for msg in self.ublox_raw:
|
||||
ur_pm.send(msg.which(), msg.as_builder())
|
||||
time.sleep(0.001)
|
||||
rcv_msgs += messaging.drain_sock(ugs)
|
||||
|
||||
time.sleep(0.1)
|
||||
rcv_msgs += messaging.drain_sock(ugs)
|
||||
return rcv_msgs
|
||||
|
||||
# replay twice to enforce cutover data on rewind
|
||||
rcv_msgs = replay_segment()
|
||||
rcv_msgs += replay_segment()
|
||||
|
||||
ephems_cnt = sum(m.ubloxGnss.which() == 'ephemeris' for m in rcv_msgs)
|
||||
self.assertEqual(ephems_cnt, 15)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
4
tools/gpstest/.gitignore
vendored
4
tools/gpstest/.gitignore
vendored
@@ -1,4 +0,0 @@
|
||||
LimeGPS/
|
||||
LimeSuite/
|
||||
hackrf/
|
||||
gps-sdr-sim/
|
||||
@@ -1,33 +0,0 @@
|
||||
# GPS test setup
|
||||
Testing the GPS receiver using GPS spoofing. At the moment only
|
||||
static location relpay is supported.
|
||||
|
||||
# Usage
|
||||
on C3 run `rpc_server.py`, on host PC run `fuzzy_testing.py`
|
||||
|
||||
`simulate_gps_signal.py` downloads the latest ephemeris file from
|
||||
https://cddis.nasa.gov/archive/gnss/data/daily/20xx/brdc/.
|
||||
|
||||
|
||||
# Hardware Setup
|
||||
* [LimeSDR USB](https://wiki.myriadrf.org/LimeSDR-USB)
|
||||
* Asus AX58BT antenna
|
||||
|
||||
# Software Setup
|
||||
* https://github.com/myriadrf/LimeSuite
|
||||
To communicate with LimeSDR the LimeSuite is needed it abstracts the direct
|
||||
communication. It also contains examples for a quick start.
|
||||
|
||||
The latest stable version (22.09) does not have the corresponding firmware
|
||||
download available at https://downloads.myriadrf.org/project/limesuite. Therefore
|
||||
version 20.10 was chosen.
|
||||
|
||||
* https://github.com/osqzss/LimeGPS
|
||||
Built on top of LimeSuite (libLimeSuite.so.20.10-1), generates the GPS signal.
|
||||
|
||||
```
|
||||
./LimeGPS -e <ephemeris file> -l <location coordinates>
|
||||
|
||||
# Example
|
||||
./LimeGPS -e /pathTo/brdc2660.22n -l 47.202028,15.740394,100
|
||||
```
|
||||
@@ -1,111 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import multiprocessing
|
||||
import rpyc
|
||||
from collections import defaultdict
|
||||
|
||||
from helper import download_rinex, exec_LimeGPS_bin
|
||||
from helper import get_random_coords, get_continuous_coords
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# this script is supposed to run on HOST PC
|
||||
# limeSDR is unreliable via c3 USB
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
|
||||
def run_lime_gps(rinex_file: str, location: str, timeout: int):
|
||||
# needs to run longer than the checker
|
||||
timeout += 10
|
||||
print(f"LimeGPS {location} {timeout}")
|
||||
p = multiprocessing.Process(target=exec_LimeGPS_bin,
|
||||
args=(rinex_file, location, timeout))
|
||||
p.start()
|
||||
return p
|
||||
|
||||
con = None
|
||||
def run_remote_checker(lat, lon, alt, duration, ip_addr):
|
||||
global con
|
||||
try:
|
||||
con = rpyc.connect(ip_addr, 18861)
|
||||
con._config['sync_request_timeout'] = duration+20
|
||||
except ConnectionRefusedError:
|
||||
print("could not run remote checker is 'rpc_server.py' running???")
|
||||
return False, None, None
|
||||
|
||||
matched, log, info = con.root.exposed_run_checker(lat, lon, alt,
|
||||
timeout=duration)
|
||||
con.close() # TODO: might wanna fetch more logs here
|
||||
con = None
|
||||
|
||||
print(f"Remote Checker: {log} {info}")
|
||||
return matched, log, info
|
||||
|
||||
|
||||
stats = defaultdict(int) # type: ignore
|
||||
keys = ['success', 'failed', 'ublox_fail', 'proc_crash', 'checker_crash']
|
||||
|
||||
def print_report():
|
||||
print("\nFuzzy testing report summary:")
|
||||
for k in keys:
|
||||
print(f" {k}: {stats[k]}")
|
||||
|
||||
|
||||
def update_stats(matched, log, info):
|
||||
if matched:
|
||||
stats['success'] += 1
|
||||
return
|
||||
|
||||
stats['failed'] += 1
|
||||
if log == "PROC CRASH":
|
||||
stats['proc_crash'] += 1
|
||||
if log == "CHECKER CRASHED":
|
||||
stats['checker_crash'] += 1
|
||||
if log == "TIMEOUT":
|
||||
stats['ublox_fail'] += 1
|
||||
|
||||
|
||||
def main(ip_addr, continuous_mode, timeout, pos):
|
||||
rinex_file = download_rinex()
|
||||
|
||||
lat, lon, alt = pos
|
||||
if lat == 0 and lon == 0 and alt == 0:
|
||||
lat, lon, alt = get_random_coords(47.2020, 15.7403)
|
||||
|
||||
try:
|
||||
while True:
|
||||
# spoof random location
|
||||
spoof_proc = run_lime_gps(rinex_file, f"{lat},{lon},{alt}", timeout)
|
||||
|
||||
# remote checker execs blocking
|
||||
matched, log, info = run_remote_checker(lat, lon, alt, timeout, ip_addr)
|
||||
update_stats(matched, log, info)
|
||||
spoof_proc.terminate()
|
||||
spoof_proc = None
|
||||
|
||||
if continuous_mode:
|
||||
lat, lon, alt = get_continuous_coords(lat, lon, alt)
|
||||
else:
|
||||
lat, lon, alt = get_random_coords(lat, lon)
|
||||
except KeyboardInterrupt:
|
||||
if spoof_proc is not None:
|
||||
spoof_proc.terminate()
|
||||
|
||||
if con is not None and not con.closed:
|
||||
con.root.exposed_kill_procs()
|
||||
con.close()
|
||||
|
||||
print_report()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="Fuzzy test GPS stack with random locations.")
|
||||
parser.add_argument("ip_addr", type=str)
|
||||
parser.add_argument("-c", "--contin", type=bool, nargs='?', default=False, help='Continous location change')
|
||||
parser.add_argument("-t", "--timeout", type=int, nargs='?', default=180, help='Timeout to get location')
|
||||
|
||||
# for replaying a location
|
||||
parser.add_argument("lat", type=float, nargs='?', default=0)
|
||||
parser.add_argument("lon", type=float, nargs='?', default=0)
|
||||
parser.add_argument("alt", type=float, nargs='?', default=0)
|
||||
args = parser.parse_args()
|
||||
main(args.ip_addr, args.contin, args.timeout, (args.lat, args.lon, args.alt))
|
||||
@@ -1,53 +0,0 @@
|
||||
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
|
||||
|
||||
|
||||
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, '/tmp/gpstest/', ConstellationId.GPS)
|
||||
|
||||
|
||||
def exec_LimeGPS_bin(rinex_file: str, location: str, duration: int):
|
||||
# this functions should never return, cause return means, timeout is
|
||||
# reached or it crashed
|
||||
try:
|
||||
cmd = ["LimeGPS/LimeGPS", "-e", rinex_file, "-l", location]
|
||||
sp.check_output(cmd, timeout=duration)
|
||||
except sp.TimeoutExpired:
|
||||
print("LimeGPS timeout reached!")
|
||||
except Exception as e:
|
||||
print(f"LimeGPS crashed: {str(e)}")
|
||||
|
||||
|
||||
def get_random_coords(lat, lon) -> Tuple[float, float, 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
|
||||
alt = random.randint(-10**3, 4*10**3)
|
||||
|
||||
lat = ((lat + lat_add + 90) % 180) - 90
|
||||
lon = ((lon + lon_add + 180) % 360) - 180
|
||||
return round(lat, 5), round(lon, 5), alt
|
||||
|
||||
|
||||
def get_continuous_coords(lat, lon, alt) -> Tuple[float, float, int]:
|
||||
# continuously move around the world
|
||||
lat_add = random.random()*0.01
|
||||
lon_add = random.random()*0.01
|
||||
alt_add = random.randint(-100, 100)
|
||||
|
||||
lat = ((lat + lat_add + 90) % 180) - 90
|
||||
lon = ((lon + lon_add + 180) % 360) - 180
|
||||
alt += alt_add
|
||||
return round(lat, 5), round(lon, 5), alt
|
||||
@@ -1,44 +0,0 @@
|
||||
diff --git a/host/hackrf-tools/src/CMakeLists.txt b/host/hackrf-tools/src/CMakeLists.txt
|
||||
index 7115151c..a51388ba 100644
|
||||
--- a/host/hackrf-tools/src/CMakeLists.txt
|
||||
+++ b/host/hackrf-tools/src/CMakeLists.txt
|
||||
@@ -23,20 +23,20 @@
|
||||
|
||||
set(INSTALL_DEFAULT_BINDIR "bin" CACHE STRING "Appended to CMAKE_INSTALL_PREFIX")
|
||||
|
||||
-find_package(FFTW REQUIRED)
|
||||
-include_directories(${FFTW_INCLUDES})
|
||||
-get_filename_component(FFTW_LIBRARY_DIRS ${FFTW_LIBRARIES} DIRECTORY)
|
||||
-link_directories(${FFTW_LIBRARY_DIRS})
|
||||
+#find_package(FFTW REQUIRED)
|
||||
+#include_directories(${FFTW_INCLUDES})
|
||||
+#get_filename_component(FFTW_LIBRARY_DIRS ${FFTW_LIBRARIES} DIRECTORY)
|
||||
+#link_directories(${FFTW_LIBRARY_DIRS})
|
||||
|
||||
SET(TOOLS
|
||||
hackrf_transfer
|
||||
- hackrf_spiflash
|
||||
- hackrf_cpldjtag
|
||||
+ #hackrf_spiflash
|
||||
+ #hackrf_cpldjtag
|
||||
hackrf_info
|
||||
- hackrf_debug
|
||||
- hackrf_clock
|
||||
- hackrf_sweep
|
||||
- hackrf_operacake
|
||||
+ #hackrf_debug
|
||||
+ #hackrf_clock
|
||||
+ #hackrf_sweep
|
||||
+ #hackrf_operacake
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
@@ -45,7 +45,7 @@ if(MSVC)
|
||||
)
|
||||
LIST(APPEND TOOLS_LINK_LIBS ${FFTW_LIBRARIES})
|
||||
else()
|
||||
- LIST(APPEND TOOLS_LINK_LIBS m fftw3f)
|
||||
+ LIST(APPEND TOOLS_LINK_LIBS m)# fftw3f)
|
||||
endif()
|
||||
|
||||
if(NOT libhackrf_SOURCE_DIR)
|
||||
@@ -1,13 +0,0 @@
|
||||
diff --git a/gpssim.h b/gpssim.h
|
||||
index c30b227..2ae0802 100644
|
||||
--- a/gpssim.h
|
||||
+++ b/gpssim.h
|
||||
@@ -75,7 +75,7 @@
|
||||
#define SC08 (8)
|
||||
#define SC16 (16)
|
||||
|
||||
-#define EPHEM_ARRAY_SIZE (13) // for daily GPS broadcast ephemers file (brdc)
|
||||
+#define EPHEM_ARRAY_SIZE (20) // for daily GPS broadcast ephemers file (brdc)
|
||||
|
||||
/*! \brief Structure representing GPS time */
|
||||
typedef struct
|
||||
@@ -1,11 +0,0 @@
|
||||
diff --git a/makefile b/makefile
|
||||
index 51bfabf..d0ea1eb 100644
|
||||
--- a/makefile
|
||||
+++ b/makefile
|
||||
@@ -1,5 +1,4 @@
|
||||
CC=gcc -O2 -Wall
|
||||
|
||||
all: limegps.c gpssim.c
|
||||
- $(CC) -o LimeGPS limegps.c gpssim.c -lm -lpthread -lLimeSuite
|
||||
-
|
||||
+ $(CC) -o LimeGPS limegps.c gpssim.c -lm -lpthread -lLimeSuite -I../LimeSuite/src -L../LimeSuite/builddir/src -Wl,-rpath="$(PWD)/../LimeSuite/builddir/src"
|
||||
@@ -1,13 +0,0 @@
|
||||
diff --git a/src/lms7002m/LMS7002M_RxTxCalibrations.cpp b/src/lms7002m/LMS7002M_RxTxCalibrations.cpp
|
||||
index 41a37044..ac29c6b6 100644
|
||||
--- a/src/lms7002m/LMS7002M_RxTxCalibrations.cpp
|
||||
+++ b/src/lms7002m/LMS7002M_RxTxCalibrations.cpp
|
||||
@@ -254,7 +254,7 @@ int LMS7002M::CalibrateTx(float_type bandwidth_Hz, bool useExtLoopback)
|
||||
mcuControl->RunProcedure(useExtLoopback ? MCU_FUNCTION_CALIBRATE_TX_EXTLOOPB : MCU_FUNCTION_CALIBRATE_TX);
|
||||
status = mcuControl->WaitForMCU(1000);
|
||||
if(status != MCU_BD::MCU_NO_ERROR)
|
||||
- return ReportError(EINVAL, "Tx Calibration: MCU error %i (%s)", status, MCU_BD::MCUStatusMessage(status));
|
||||
+ return -1; //ReportError(EINVAL, "Tx Calibration: MCU error %i (%s)", status, MCU_BD::MCUStatusMessage(status));
|
||||
}
|
||||
|
||||
//sync registers to cache
|
||||
@@ -1,13 +0,0 @@
|
||||
diff --git a/src/FPGA_common/FPGA_common.cpp b/src/FPGA_common/FPGA_common.cpp
|
||||
index 4e81f33e..7381c475 100644
|
||||
--- a/src/FPGA_common/FPGA_common.cpp
|
||||
+++ b/src/FPGA_common/FPGA_common.cpp
|
||||
@@ -946,7 +946,7 @@ double FPGA::DetectRefClk(double fx3Clk)
|
||||
|
||||
if (i == 0)
|
||||
return -1;
|
||||
- lime::info("Reference clock %1.2f MHz", clkTbl[i - 1] / 1e6);
|
||||
+ //lime::info("Reference clock %1.2f MHz", clkTbl[i - 1] / 1e6);
|
||||
return clkTbl[i - 1];
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# NOTE: can only run inside limeGPS test box!
|
||||
|
||||
# run limeGPS with random static location
|
||||
timeout 300 ./simulate_gps_signal.py 32.7518 -117.1962 &
|
||||
gps_PID=$(ps -aux | grep -m 1 "timeout 300" | awk '{print $2}')
|
||||
|
||||
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
|
||||
@@ -1,25 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
|
||||
cd $DIR
|
||||
|
||||
if [ ! -d LimeSuite ]; then
|
||||
git clone https://github.com/myriadrf/LimeSuite.git
|
||||
cd LimeSuite
|
||||
# checkout latest version which has firmware updates available
|
||||
git checkout v20.10.0
|
||||
git apply ../patches/limeSuite/*
|
||||
mkdir builddir && cd builddir
|
||||
cmake -DCMAKE_BUILD_TYPE=Release ..
|
||||
make -j4
|
||||
cd ../..
|
||||
fi
|
||||
|
||||
if [ ! -d LimeGPS ]; then
|
||||
git clone https://github.com/osqzss/LimeGPS.git
|
||||
cd LimeGPS
|
||||
git apply ../patches/limeGPS/*
|
||||
make
|
||||
cd ..
|
||||
fi
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
|
||||
cd $DIR
|
||||
|
||||
if [ ! -d gps-sdr-sim ]; then
|
||||
git clone https://github.com/osqzss/gps-sdr-sim.git
|
||||
cd gps-sdr-sim
|
||||
make
|
||||
cd ..
|
||||
fi
|
||||
|
||||
if [ ! -d hackrf ]; then
|
||||
git clone https://github.com/greatscottgadgets/hackrf.git
|
||||
cd hackrf/host
|
||||
git apply ../../patches/hackrf.patch
|
||||
cmake .
|
||||
make
|
||||
fi
|
||||
|
||||
@@ -1,151 +0,0 @@
|
||||
#!/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 run_limeSDR_loop(lat, lon, alt, contin_sim, rinex_file, timeout):
|
||||
while True:
|
||||
try:
|
||||
# TODO: add starttime setting and altitude
|
||||
# -t 2023/01/15,00:00:00 -T 2023/01/15,00:00:00
|
||||
# this needs to match the date of the navigation file
|
||||
print(f"starting LimeGPS, Location: {lat} {lon} {alt}")
|
||||
cmd = ["LimeGPS/LimeGPS", "-e", rinex_file, "-l", f"{lat},{lon},{alt}"]
|
||||
print(f"CMD: {cmd}")
|
||||
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
|
||||
return
|
||||
|
||||
if contin_sim:
|
||||
lat, lon = get_continuous_coords(lat, lon)
|
||||
else:
|
||||
lat, lon = get_random_coords(lat, lon)
|
||||
|
||||
def run_hackRF_loop(lat, lon, rinex_file, timeout):
|
||||
|
||||
if timeout is not None:
|
||||
print("no jump mode for hackrf!")
|
||||
return
|
||||
|
||||
try:
|
||||
print(f"starting gps-sdr-sim, Location: {lat},{lon}")
|
||||
# create 30second file and replay with hackrf endless
|
||||
cmd = ["gps-sdr-sim/gps-sdr-sim", "-e", rinex_file, "-l", f"{lat},{lon},-200", "-d", "30"]
|
||||
sp.check_output(cmd, stderr=sp.PIPE, timeout=timeout)
|
||||
# created in current working directory
|
||||
except Exception:
|
||||
print("Failed to generate gpssim.bin")
|
||||
|
||||
try:
|
||||
print("starting hackrf_transfer")
|
||||
# create 30second file and replay with hackrf endless
|
||||
cmd = ["hackrf/host/hackrf-tools/src/hackrf_transfer", "-t", "gpssim.bin",
|
||||
"-f", "1575420000", "-s", "2600000", "-a", "1", "-R"]
|
||||
sp.check_output(cmd, stderr=sp.PIPE, timeout=timeout)
|
||||
except KeyboardInterrupt:
|
||||
print("stopping hackrf_transfer")
|
||||
return
|
||||
except Exception as e:
|
||||
print(f"hackrf_transfer crashed:{str(e)}")
|
||||
|
||||
|
||||
def main(lat, lon, alt, jump_sim, contin_sim, hackrf_mode):
|
||||
|
||||
if hackrf_mode:
|
||||
if not os.path.exists('hackrf'):
|
||||
print("hackrf not found run 'setup_hackrf.sh' first")
|
||||
return
|
||||
|
||||
if not os.path.exists('gps-sdr-sim'):
|
||||
print("gps-sdr-sim not found run 'setup_hackrf.sh' first")
|
||||
return
|
||||
|
||||
output = sp.check_output(["hackrf/host/hackrf-tools/src/hackrf_info"])
|
||||
if output.strip() == b"" or b"No HackRF boards found." in output:
|
||||
print("No HackRF boards found!")
|
||||
return
|
||||
|
||||
else:
|
||||
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
|
||||
|
||||
output = sp.check_output(["LimeSuite/builddir/LimeUtil/LimeUtil", "--find"])
|
||||
if output.strip() == b"":
|
||||
print("No LimeSDR device found!")
|
||||
return
|
||||
print(f"Device: {output.strip().decode('utf-8')}")
|
||||
|
||||
if lat == 0 and lon == 0:
|
||||
lat, lon = get_random_coords(47.2020, 15.7403)
|
||||
|
||||
rinex_file = download_rinex()
|
||||
|
||||
timeout = None
|
||||
if jump_sim:
|
||||
timeout = 30
|
||||
|
||||
if hackrf_mode:
|
||||
run_hackRF_loop(lat, lon, rinex_file, timeout)
|
||||
else:
|
||||
run_limeSDR_loop(lat, lon, alt, contin_sim, rinex_file, timeout)
|
||||
|
||||
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("alt", 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")
|
||||
parser.add_argument("--hackrf", action="store_true", help="hackrf mode (DEFAULT: LimeSDR)")
|
||||
args = parser.parse_args()
|
||||
main(args.lat, args.lon, args.alt, args.jump, args.contin, args.hackrf)
|
||||
@@ -1,189 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import pytest
|
||||
import time
|
||||
import unittest
|
||||
import struct
|
||||
|
||||
from openpilot.common.params import Params
|
||||
import cereal.messaging as messaging
|
||||
import openpilot.system.sensord.pigeond as pd
|
||||
from openpilot.selfdrive.test.helpers import with_processes
|
||||
|
||||
|
||||
def read_events(service, duration_sec):
|
||||
service_sock = messaging.sub_sock(service, timeout=0.1)
|
||||
start_time_sec = time.monotonic()
|
||||
events = []
|
||||
while time.monotonic() - start_time_sec < duration_sec:
|
||||
events += messaging.drain_sock(service_sock)
|
||||
time.sleep(0.1)
|
||||
|
||||
assert len(events) != 0, f"No '{service}'events collected!"
|
||||
return events
|
||||
|
||||
|
||||
def create_backup(pigeon):
|
||||
# controlled GNSS stop
|
||||
pigeon.send(b"\xB5\x62\x06\x04\x04\x00\x00\x00\x08\x00\x16\x74")
|
||||
|
||||
# store almanac in flash
|
||||
pigeon.send(b"\xB5\x62\x09\x14\x04\x00\x00\x00\x00\x00\x21\xEC")
|
||||
try:
|
||||
if not pigeon.wait_for_ack(ack=pd.UBLOX_SOS_ACK, nack=pd.UBLOX_SOS_NACK):
|
||||
raise RuntimeError("Could not store almanac")
|
||||
except TimeoutError:
|
||||
pass
|
||||
|
||||
|
||||
def verify_ubloxgnss_data(socket: messaging.SubSocket, max_time: int):
|
||||
start_time = 0
|
||||
end_time = 0
|
||||
events = messaging.drain_sock(socket)
|
||||
assert len(events) != 0, "no ublxGnss measurements"
|
||||
|
||||
for event in events:
|
||||
if event.ubloxGnss.which() != "measurementReport":
|
||||
continue
|
||||
|
||||
if start_time == 0:
|
||||
start_time = event.logMonoTime
|
||||
|
||||
if event.ubloxGnss.measurementReport.numMeas != 0:
|
||||
end_time = event.logMonoTime
|
||||
break
|
||||
|
||||
assert end_time != 0, "no ublox measurements received!"
|
||||
|
||||
ttfm = (end_time - start_time)/1e9
|
||||
assert ttfm < max_time, f"Time to first measurement > {max_time}s, {ttfm}"
|
||||
|
||||
# check for satellite count in measurements
|
||||
sat_count = []
|
||||
end_id = events.index(event)# pylint:disable=undefined-loop-variable
|
||||
for event in events[end_id:]:
|
||||
if event.ubloxGnss.which() == "measurementReport":
|
||||
sat_count.append(event.ubloxGnss.measurementReport.numMeas)
|
||||
|
||||
num_sat = int(sum(sat_count)/len(sat_count))
|
||||
assert num_sat >= 5, f"Not enough satellites {num_sat} (TestBox setup!)"
|
||||
|
||||
|
||||
def verify_gps_location(socket: messaging.SubSocket, max_time: int):
|
||||
events = messaging.drain_sock(socket)
|
||||
assert len(events) != 0, "no gpsLocationExternal measurements"
|
||||
|
||||
start_time = events[0].logMonoTime
|
||||
end_time = 0
|
||||
for event in events:
|
||||
gps_valid = event.gpsLocationExternal.flags % 2
|
||||
|
||||
if gps_valid:
|
||||
end_time = event.logMonoTime
|
||||
break
|
||||
|
||||
assert end_time != 0, "GPS location never converged!"
|
||||
|
||||
ttfl = (end_time - start_time)/1e9
|
||||
assert ttfl < max_time, f"Time to first location > {max_time}s, {ttfl}"
|
||||
|
||||
hacc = events[-1].gpsLocationExternal.accuracy
|
||||
vacc = events[-1].gpsLocationExternal.verticalAccuracy
|
||||
assert hacc < 20, f"Horizontal accuracy too high, {hacc}"
|
||||
assert vacc < 45, f"Vertical accuracy too high, {vacc}"
|
||||
|
||||
|
||||
def verify_time_to_first_fix(pigeon):
|
||||
# get time to first fix from nav status message
|
||||
nav_status = b""
|
||||
while True:
|
||||
pigeon.send(b"\xb5\x62\x01\x03\x00\x00\x04\x0d")
|
||||
nav_status = pigeon.receive()
|
||||
if nav_status[:4] == b"\xb5\x62\x01\x03":
|
||||
break
|
||||
|
||||
values = struct.unpack("<HHHIBBBBIIH", nav_status[:24])
|
||||
ttff = values[8]/1000
|
||||
# srms = values[9]/1000
|
||||
assert ttff < 40, f"Time to first fix > 40s, {ttff}"
|
||||
|
||||
|
||||
@pytest.mark.tici
|
||||
class TestGPS(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
ublox_available = Params().get_bool("UbloxAvailable")
|
||||
if not ublox_available:
|
||||
raise unittest.SkipTest
|
||||
|
||||
|
||||
def tearDown(self):
|
||||
pd.set_power(False)
|
||||
|
||||
@with_processes(['ubloxd'])
|
||||
def test_a_ublox_reset(self):
|
||||
|
||||
pigeon, pm = pd.create_pigeon()
|
||||
pd.init_baudrate(pigeon)
|
||||
assert pigeon.reset_device(), "Could not reset device!"
|
||||
|
||||
pd.initialize_pigeon(pigeon)
|
||||
|
||||
ugs = messaging.sub_sock("ubloxGnss", timeout=0.1)
|
||||
gle = messaging.sub_sock("gpsLocationExternal", timeout=0.1)
|
||||
|
||||
# receive some messages (restart after cold start takes up to 30seconds)
|
||||
pd.run_receiving(pigeon, pm, 60)
|
||||
|
||||
# store almanac for next test
|
||||
create_backup(pigeon)
|
||||
|
||||
verify_ubloxgnss_data(ugs, 60)
|
||||
verify_gps_location(gle, 60)
|
||||
|
||||
# skip for now, this might hang for a while
|
||||
#verify_time_to_first_fix(pigeon)
|
||||
|
||||
|
||||
@with_processes(['ubloxd'])
|
||||
def test_b_ublox_almanac(self):
|
||||
pigeon, pm = pd.create_pigeon()
|
||||
pd.init_baudrate(pigeon)
|
||||
|
||||
# device cold start
|
||||
pigeon.send(b"\xb5\x62\x06\x04\x04\x00\xff\xff\x00\x00\x0c\x5d")
|
||||
time.sleep(1) # wait for cold start
|
||||
pd.init_baudrate(pigeon)
|
||||
|
||||
# clear configuration
|
||||
pigeon.send_with_ack(b"\xb5\x62\x06\x09\x0d\x00\x00\x00\x1f\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x17\x71\x5b")
|
||||
|
||||
# restoring almanac backup
|
||||
pigeon.send(b"\xB5\x62\x09\x14\x00\x00\x1D\x60")
|
||||
status = pigeon.wait_for_backup_restore_status()
|
||||
assert status == 2, "Could not restore almanac backup"
|
||||
|
||||
pd.initialize_pigeon(pigeon)
|
||||
|
||||
ugs = messaging.sub_sock("ubloxGnss", timeout=0.1)
|
||||
gle = messaging.sub_sock("gpsLocationExternal", timeout=0.1)
|
||||
|
||||
pd.run_receiving(pigeon, pm, 15)
|
||||
verify_ubloxgnss_data(ugs, 15)
|
||||
verify_gps_location(gle, 20)
|
||||
|
||||
|
||||
@with_processes(['ubloxd'])
|
||||
def test_c_ublox_startup(self):
|
||||
pigeon, pm = pd.create_pigeon()
|
||||
pd.init_baudrate(pigeon)
|
||||
pd.initialize_pigeon(pigeon)
|
||||
|
||||
ugs = messaging.sub_sock("ubloxGnss", timeout=0.1)
|
||||
gle = messaging.sub_sock("gpsLocationExternal", timeout=0.1)
|
||||
pd.run_receiving(pigeon, pm, 10)
|
||||
verify_ubloxgnss_data(ugs, 10)
|
||||
verify_gps_location(gle, 10)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -1,78 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import pytest
|
||||
import time
|
||||
import unittest
|
||||
import subprocess as sp
|
||||
|
||||
from openpilot.common.params import Params
|
||||
import cereal.messaging as messaging
|
||||
from openpilot.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
|
||||
|
||||
|
||||
@pytest.mark.tici
|
||||
class TestGPS(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
ublox_available = Params().get_bool("UbloxAvailable")
|
||||
if ublox_available:
|
||||
raise unittest.SkipTest
|
||||
|
||||
def test_a_quectel_cold_start(self):
|
||||
# delete assistance data to enforce cold start for GNSS
|
||||
# testing shows that this takes up to 20min
|
||||
|
||||
_, 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*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):
|
||||
managed_processes['rawgpsd'].start()
|
||||
start_time = time.monotonic()
|
||||
glo = messaging.sub_sock("gpsLocation", timeout=0.1)
|
||||
|
||||
timeout = 10*60 # 1 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()
|
||||
@@ -22,8 +22,6 @@ COPY ./body ${OPENPILOT_PATH}/body
|
||||
COPY ./third_party ${OPENPILOT_PATH}/third_party
|
||||
COPY ./site_scons ${OPENPILOT_PATH}/site_scons
|
||||
COPY ./rednose ${OPENPILOT_PATH}/rednose
|
||||
COPY ./laika_repo ${OPENPILOT_PATH}/laika_repo
|
||||
RUN ln -s ${OPENPILOT_PATH}/laika_repo/laika/ ${OPENPILOT_PATH}/laika
|
||||
COPY ./common ${OPENPILOT_PATH}/common
|
||||
COPY ./opendbc ${OPENPILOT_PATH}/opendbc
|
||||
COPY ./cereal ${OPENPILOT_PATH}/cereal
|
||||
|
||||
Reference in New Issue
Block a user