Laikad: the basics for ublox msg processing (#24359)
	
		
	
				
					
				
			* Add laikad that receives ublox messages and publishes corrected measurements and position fix * types * cleanup * laikad version 1 with uncorrected measurements * push * Fix glonass frequency and delete redundant test * Update after cereal and cleanup * Add test, fix laikad and remove process replay for now * update laika * add hatanaka to packages. Used to decompress orbit data * Fix pippull/24404/head^2
							parent
							
								
									df8f024e19
								
							
						
					
					
						commit
						b64fe6e339
					
				
				 5 changed files with 170 additions and 3 deletions
			
			
		| @ -1 +1 @@ | ||||
| Subproject commit 226adc655e1488474468a97ab4a7705aad7e5837 | ||||
| Subproject commit 1fbc6780d5184efd5ccf4518a01fe947ffbb4ba0 | ||||
| @ -0,0 +1,84 @@ | ||||
| #!/usr/bin/env python3 | ||||
| from typing import List | ||||
| 
 | ||||
| from cereal import log, messaging | ||||
| from laika import AstroDog | ||||
| from laika.helpers import UbloxGnssId | ||||
| from laika.raw_gnss import GNSSMeasurement, calc_pos_fix, correct_measurements, process_measurements, read_raw_ublox | ||||
| 
 | ||||
| 
 | ||||
| def correct_and_pos_fix(processed_measurements: List[GNSSMeasurement], dog: AstroDog): | ||||
|   # pos fix needs more than 5 processed_measurements | ||||
|   pos_fix = calc_pos_fix(processed_measurements) | ||||
| 
 | ||||
|   if len(pos_fix) == 0: | ||||
|     return [], [] | ||||
|   est_pos = pos_fix[0][:3] | ||||
|   corrected = correct_measurements(processed_measurements, est_pos, dog) | ||||
|   return calc_pos_fix(corrected), corrected | ||||
| 
 | ||||
| 
 | ||||
| def process_ublox_msg(ublox_msg, dog, ublox_mono_time: int): | ||||
|   if ublox_msg.which == 'measurementReport': | ||||
|     report = ublox_msg.measurementReport | ||||
|     if len(report.measurements) == 0: | ||||
|       return None | ||||
|     new_meas = read_raw_ublox(report) | ||||
|     processed_measurements = process_measurements(new_meas, dog) | ||||
| 
 | ||||
|     corrected = correct_and_pos_fix(processed_measurements, dog) | ||||
|     pos_fix, _ = corrected | ||||
|     # todo send corrected messages instead of processed_measurements. Need fix for when having less than 6 measurements | ||||
|     correct_meas_msgs = [create_measurement_msg(m) for m in processed_measurements] | ||||
|     # pos fix can be an empty list if not enough correct measurements are available | ||||
|     if len(pos_fix) > 0: | ||||
|       corrected_pos = pos_fix[0][:3].tolist() | ||||
|     else: | ||||
|       corrected_pos = [0., 0., 0.] | ||||
|     dat = messaging.new_message('gnssMeasurements') | ||||
|     dat.gnssMeasurements = { | ||||
|       "position": corrected_pos, | ||||
|       "ubloxMonoTime": ublox_mono_time, | ||||
|       "correctedMeasurements": correct_meas_msgs | ||||
|     } | ||||
|     return dat | ||||
| 
 | ||||
| 
 | ||||
| def create_measurement_msg(meas: GNSSMeasurement): | ||||
|   c = log.GnssMeasurements.CorrectedMeasurement.new_message() | ||||
|   ublox_gnss_id = meas.ublox_gnss_id | ||||
|   if ublox_gnss_id is None: | ||||
|     # todo never happens will fix in later pr | ||||
|     ublox_gnss_id = UbloxGnssId.GPS | ||||
|   c.constellationId = ublox_gnss_id.value | ||||
|   c.svId = int(meas.prn[1:]) | ||||
|   c.glonassFrequency = meas.glonass_freq if meas.ublox_gnss_id == UbloxGnssId.GLONASS else 0 | ||||
|   c.pseudorange = float(meas.observables['C1C'])  # todo should be observables_final when using corrected measurements | ||||
|   c.pseudorangeStd = float(meas.observables_std['C1C']) | ||||
|   c.pseudorangeRate = float(meas.observables['D1C'])  # todo should be observables_final when using corrected measurements | ||||
|   c.pseudorangeRateStd = float(meas.observables_std['D1C']) | ||||
|   c.satPos = meas.sat_pos_final.tolist() | ||||
|   c.satVel = meas.sat_vel.tolist() | ||||
|   return c | ||||
| 
 | ||||
| 
 | ||||
| def main(): | ||||
|   dog = AstroDog() | ||||
|   sm = messaging.SubMaster(['ubloxGnss']) | ||||
|   pm = messaging.PubMaster(['gnssMeasurements']) | ||||
| 
 | ||||
|   while True: | ||||
|     sm.update() | ||||
| 
 | ||||
|     # Todo if no internet available use latest ephemeris | ||||
|     if sm.updated['ubloxGnss']: | ||||
|       ublox_msg = sm['ubloxGnss'] | ||||
|       msg = process_ublox_msg(ublox_msg, dog, sm.logMonoTime['ubloxGnss']) | ||||
|       if msg is None: | ||||
|         msg = messaging.new_message('gnssMeasurements') | ||||
|       pm.send('gnssMeasurements', msg) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
|   main() | ||||
| @ -0,0 +1,23 @@ | ||||
| #!/usr/bin/env python3 | ||||
| import unittest | ||||
| from datetime import datetime | ||||
| 
 | ||||
| from laika.helpers import UbloxGnssId | ||||
| 
 | ||||
| from laika.gps_time import GPSTime | ||||
| from laika.raw_gnss import GNSSMeasurement | ||||
| from selfdrive.locationd.laikad import create_measurement_msg | ||||
| 
 | ||||
| 
 | ||||
| class TestLaikad(unittest.TestCase): | ||||
| 
 | ||||
|   def test_create_msg_without_errors(self): | ||||
|     gpstime = GPSTime.from_datetime(datetime.now()) | ||||
|     meas = GNSSMeasurement('G01', gpstime.week, gpstime.tow, {'C1C': 0., 'D1C': 0.}, {'C1C': 0., 'D1C': 0.}, ublox_gnss_id=UbloxGnssId.GPS) | ||||
|     msg = create_measurement_msg(meas) | ||||
| 
 | ||||
|     self.assertEqual(msg.constellationId, 'gps') | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
|   unittest.main() | ||||
					Loading…
					
					
				
		Reference in new issue