def fingerprint(logcan, sendcan, has_relay): if has_relay: # Vin query only reliably works thorugh OBDII bus = 1 addr, vin = get_vin(logcan, sendcan, bus) _, car_fw = get_fw_versions(logcan, sendcan, bus) else: vin = VIN_UNKNOWN _, car_fw = set(), [] cloudlog.warning("VIN %s", vin) Params().put("CarVin", vin) finger = gen_empty_fingerprint() candidate_cars = {i: all_known_cars() for i in [0, 1] } # attempt fingerprint on both bus 0 and 1 frame = 0 frame_fingerprint = 10 # 0.1s car_fingerprint = None done = False while not done: a = messaging.get_one_can(logcan) for can in a.can: # need to independently try to fingerprint both bus 0 and 1 to work # for the combo black_panda and honda_bosch. Ignore extended messages # and VIN query response. # Include bus 2 for toyotas to disambiguate cars using camera messages # (ideally should be done for all cars but we can't for Honda Bosch) if can.src in range(0, 4): finger[can.src][can.address] = len(can.dat) for b in candidate_cars: if (can.src == b or (only_toyota_left(candidate_cars[b]) and can.src == 2)) and \ can.address < 0x800 and can.address not in [0x7df, 0x7e0, 0x7e8]: candidate_cars[b] = eliminate_incompatible_cars( can, candidate_cars[b]) # if we only have one car choice and the time since we got our first # message has elapsed, exit for b in candidate_cars: # Toyota needs higher time to fingerprint, since DSU does not broadcast immediately if only_toyota_left(candidate_cars[b]): frame_fingerprint = 100 # 1s if len(candidate_cars[b]) == 1: if frame > frame_fingerprint: # fingerprint done car_fingerprint = candidate_cars[b][0] # bail if no cars left or we've been waiting for more than 2s failed = all(len(cc) == 0 for cc in candidate_cars.values()) or frame > 200 succeeded = car_fingerprint is not None done = failed or succeeded frame += 1 cloudlog.warning("fingerprinted %s", car_fingerprint) return car_fingerprint, finger, vin, car_fw
class TestCarInterfaces(unittest.TestCase): @parameterized.expand([(car, ) for car in all_known_cars()]) def test_car_interfaces(self, car_name): print(car_name) fingerprint = FINGERPRINTS[car_name][0] CarInterface, CarController, CarState = interfaces[car_name] fingerprints = { 0: fingerprint, 1: fingerprint, 2: fingerprint, } car_fw = [] car_params = CarInterface.get_params(car_name, fingerprints, car_fw) car_interface = CarInterface(car_params, CarController, CarState) assert car_params assert car_interface self.assertGreater(car_params.mass, 1) self.assertGreater(car_params.steerRateCost, 1e-3) if car_params.steerControlType != car.CarParams.SteerControlType.angle: tuning = car_params.lateralTuning.which() if tuning == 'pid': self.assertTrue(len(car_params.lateralTuning.pid.kpV)) elif tuning == 'lqr': self.assertTrue(len(car_params.lateralTuning.lqr.a)) elif tuning == 'indi': self.assertTrue( len(car_params.lateralTuning.indi.outerLoopGainV)) # Run car interface CC = car.CarControl.new_message() for _ in range(10): car_interface.update(CC, []) car_interface.apply(CC) car_interface.apply(CC) CC = car.CarControl.new_message() CC.enabled = True for _ in range(10): car_interface.update(CC, []) car_interface.apply(CC) car_interface.apply(CC) # Test radar interface RadarInterface = importlib.import_module( 'selfdrive.car.%s.radar_interface' % car_params.carName).RadarInterface radar_interface = RadarInterface(car_params) assert radar_interface # Run radar interface once radar_interface.update([]) if not car_params.radarOffCan and hasattr( radar_interface, '_update') and hasattr( radar_interface, 'trigger_msg'): radar_interface._update([radar_interface.trigger_msg])
def test_car_interfaces(self): all_cars = all_known_cars() for car_name in all_cars: fingerprint = FINGERPRINTS[car_name][0] CarInterface, CarController, CarState = interfaces[car_name] fingerprints = { 0: fingerprint, 1: fingerprint, 2: fingerprint, } car_fw = [] for has_relay in [True, False]: car_params = CarInterface.get_params(car_name, fingerprints, has_relay, car_fw) car_interface = CarInterface(car_params, CarController, CarState) assert car_params assert car_interface # Run car interface CC = car.CarControl.new_message() for _ in range(10): car_interface.update(CC, []) car_interface.apply(CC) car_interface.apply(CC) CC = car.CarControl.new_message() CC.enabled = True for _ in range(10): car_interface.update(CC, []) car_interface.apply(CC) car_interface.apply(CC) # Test radar interface RadarInterface = importlib.import_module( 'selfdrive.car.%s.radar_interface' % car_params.carName).RadarInterface radar_interface = RadarInterface(car_params) assert radar_interface # Run radar interface once radar_interface.update([]) if hasattr(radar_interface, '_update') and hasattr( radar_interface, 'trigger_msg'): radar_interface._update([radar_interface.trigger_msg])
HYUNDAI.KONA, HYUNDAI.KONA_EV, TOYOTA.CAMRYH, TOYOTA.CHR, TOYOTA.CHRH, TOYOTA.HIGHLANDERH, TOYOTA.HIGHLANDERH_TSS2, ] if __name__ == "__main__": tested_procs = ["controlsd", "radard", "plannerd"] tested_socks = ["radarState", "controlsState", "carState", "plan"] tested_cars = [keys["carFingerprint"] for route, keys in routes.items()] for car_model in all_known_cars(): if car_model not in tested_cars: print("***** WARNING: %s not tested *****" % car_model) # TODO: skip these for now, but make sure any new ports get routes if car_model not in non_tested_cars: print("TEST FAILED: Missing route for car '%s'" % car_model) sys.exit(1) print("Preparing processes") for p in tested_procs: manager.prepare_managed_process(p) results = {} for route, checks in routes.items(): get_route_log(route)
HONDA.ACCORDH, ] ignore_carstate_check = [ # TODO: chrysler gas state in panda also checks wheel speed, refactor so it's only gas CHRYSLER.PACIFICA_2017_HYBRID, # TODO: get new routes for these cars, current routes are from giraffe with different buses HONDA.CRV_HYBRID, HONDA.ACCORD, HONDA.INSIGHT, HONDA.ACCORDH, ] @parameterized_class(('car_model'), [(car, ) for car in all_known_cars()]) class TestCarModel(unittest.TestCase): @classmethod def setUpClass(cls): if cls.car_model not in ROUTES: # TODO: get routes for missing cars and remove this if cls.car_model in non_tested_cars: print(f"Skipping tests for {cls.car_model}: missing route") raise unittest.SkipTest else: raise Exception(f"missing test route for car {cls.car_model}") for seg in [2, 1, 0]: try: lr = LogReader(get_url(ROUTES[cls.car_model], seg)) break
def fingerprint(logcan, sendcan): fixed_fingerprint = os.environ.get('FINGERPRINT', "") skip_fw_query = os.environ.get('SKIP_FW_QUERY', False) if not fixed_fingerprint and not skip_fw_query: # Vin query only reliably works thorugh OBDII bus = 1 cached_params = Params().get("CarParamsCache") if cached_params is not None: cached_params = car.CarParams.from_bytes(cached_params) if cached_params.carName == "mock": cached_params = None if cached_params is not None and len( cached_params.carFw ) > 0 and cached_params.carVin is not VIN_UNKNOWN: cloudlog.warning("Using cached CarParams") vin = cached_params.carVin car_fw = list(cached_params.carFw) else: cloudlog.warning("Getting VIN & FW versions") _, vin = get_vin(logcan, sendcan, bus) car_fw = get_fw_versions(logcan, sendcan, bus) fw_candidates = match_fw_to_car(car_fw) else: vin = VIN_UNKNOWN fw_candidates, car_fw = set(), [] cloudlog.warning("VIN %s", vin) Params().put("CarVin", vin) finger = gen_empty_fingerprint() candidate_cars = {i: all_known_cars() for i in [0, 1] } # attempt fingerprint on both bus 0 and 1 frame = 0 frame_fingerprint = 10 # 0.1s car_fingerprint = None done = False while not done: a = get_one_can(logcan) for can in a.can: # need to independently try to fingerprint both bus 0 and 1 to work # for the combo black_panda and honda_bosch. Ignore extended messages # and VIN query response. # Include bus 2 for toyotas to disambiguate cars using camera messages # (ideally should be done for all cars but we can't for Honda Bosch) if can.src in range(0, 4): finger[can.src][can.address] = len(can.dat) for b in candidate_cars: if (can.src == b or (only_toyota_left(candidate_cars[b]) and can.src == 2)) and \ can.address < 0x800 and can.address not in [0x7df, 0x7e0, 0x7e8]: candidate_cars[b] = eliminate_incompatible_cars( can, candidate_cars[b]) # if we only have one car choice and the time since we got our first # message has elapsed, exit for b in candidate_cars: # Toyota needs higher time to fingerprint, since DSU does not broadcast immediately if only_toyota_left(candidate_cars[b]): frame_fingerprint = 100 # 1s if len(candidate_cars[b]) == 1 and frame > frame_fingerprint: # fingerprint done car_fingerprint = candidate_cars[b][0] # bail if no cars left or we've been waiting for more than 2s failed = all(len(cc) == 0 for cc in candidate_cars.values()) or frame > 200 succeeded = car_fingerprint is not None done = failed or succeeded frame += 1 source = car.CarParams.FingerprintSource.can # If FW query returns exactly 1 candidate, use it if len(fw_candidates) == 1: car_fingerprint = list(fw_candidates)[0] source = car.CarParams.FingerprintSource.fw if fixed_fingerprint: car_fingerprint = fixed_fingerprint source = car.CarParams.FingerprintSource.fixed cloudlog.warning("fingerprinted %s", car_fingerprint) return car_fingerprint, finger, vin, car_fw, source
# TODO: get updated routes for these cars ignore_can_valid = [ HYUNDAI.SANTA_FE, ] ignore_carstate_check = [ # TODO: chrysler gas state in panda also checks wheel speed, refactor so it's only gas CHRYSLER.PACIFICA_2017_HYBRID, ] ignore_addr_checks_valid = [ GM.BUICK_REGAL, HYUNDAI.GENESIS_G70_2020, ] @parameterized_class(('car_model'), [(car,) for i, car in enumerate(sorted(all_known_cars())) if i % NUM_JOBS == JOB_ID]) class TestCarModel(unittest.TestCase): @classmethod def setUpClass(cls): if cls.car_model not in ROUTES: # TODO: get routes for missing cars and remove this if cls.car_model in non_tested_cars: print(f"Skipping tests for {cls.car_model}: missing route") raise unittest.SkipTest else: raise Exception(f"missing test route for car {cls.car_model}") params = Params() params.clear_all()
ignore_can_valid = [ HYUNDAI.GRANDEUR_IG, ] ignore_carstate_check = [ # TODO: chrysler gas state in panda also checks wheel speed, refactor so it's only gas HYUNDAI.GRANDEUR_IG, ] ignore_addr_checks_valid = [ HYUNDAI.GRANDEUR_IG, ] @parameterized_class(('car_model'), [(car, ) for i, car in enumerate(sorted(all_known_cars())) if i % NUM_JOBS == JOB_ID]) class TestCarModel(unittest.TestCase): @classmethod def setUpClass(cls): if cls.car_model not in ROUTES: # TODO: get routes for missing cars and remove this if cls.car_model in non_tested_cars: print(f"Skipping tests for {cls.car_model}: missing route") raise unittest.SkipTest else: raise Exception(f"missing test route for car {cls.car_model}") params = Params() params.clear_all()
#!/usr/bin/env python3 from selfdrive.car.fingerprints import eliminate_incompatible_cars, all_known_cars import cereal.messaging as messaging # rav4 2019 and corolla tss2 fingerprint = {896: 8, 898: 8, 900: 6, 976: 1, 1541: 8, 902: 6, 905: 8, 810: 2, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1552: 8, 1553: 8, 1556: 8, 1571: 8, 921: 8, 1056: 8, 544: 4, 1570: 8, 1059: 1, 36: 8, 37: 8, 550: 8, 935: 8, 552: 4, 170: 8, 812: 8, 944: 8, 945: 8, 562: 6, 180: 8, 1077: 8, 951: 8, 1592: 8, 1076: 8, 186: 4, 955: 8, 956: 8, 1001: 8, 705: 8, 452: 8, 1788: 8, 464: 8, 824: 8, 466: 8, 467: 8, 761: 8, 728: 8, 1572: 8, 1114: 8, 933: 8, 800: 8, 608: 8, 865: 8, 610: 8, 1595: 8, 934: 8, 998: 5, 1745: 8, 1000: 8, 764: 8, 1002: 8, 999: 7, 1789: 8, 1649: 8, 1779: 8, 1568: 8, 1017: 8, 1786: 8, 1787: 8, 1020: 8, 426: 6, 1279: 8} candidate_cars = all_known_cars() for addr, l in fingerprint.items(): dat = messaging.new_message('can', 1) msg = dat.can[0] msg.address = addr msg.dat = " " * l candidate_cars = eliminate_incompatible_cars(msg, candidate_cars) print(candidate_cars)
NUM_JOBS = int(os.environ.get("NUM_JOBS", "1")) JOB_ID = int(os.environ.get("JOB_ID", "0")) ignore_addr_checks_valid = [ GM.BUICK_REGAL, HYUNDAI.GENESIS_G70_2020, ] # build list of test cases routes_by_car = defaultdict(set) for r in routes: routes_by_car[r.car_fingerprint].add(r) test_cases: List[Tuple[str, Optional[TestRoute]]] = [] for i, c in enumerate(sorted(all_known_cars())): if i % NUM_JOBS == JOB_ID: test_cases.extend((c, r) for r in routes_by_car.get(c, (None, ))) SKIP_ENV_VAR = "SKIP_LONG_TESTS" @parameterized_class(('car_model', 'test_route'), test_cases) class TestCarModel(unittest.TestCase): @unittest.skipIf(SKIP_ENV_VAR in os.environ, f"Long running test skipped. Unset {SKIP_ENV_VAR} to run") @classmethod def setUpClass(cls): if cls.test_route is None: if cls.car_model in non_tested_cars: print(f"Skipping tests for {cls.car_model}: missing route")
def test_car_interfaces(self): all_cars = all_known_cars() for car_name in all_cars: fingerprint = FINGERPRINTS[car_name][0] CarInterface, CarController, CarState = interfaces[car_name] fingerprints = { 0: fingerprint, 1: fingerprint, 2: fingerprint, } car_fw = [] for has_relay in [True, False]: car_params = CarInterface.get_params(car_name, fingerprints, has_relay, car_fw) car_interface = CarInterface(car_params, CarController, CarState) assert car_params assert car_interface self.assertGreater(car_params.mass, 1) self.assertGreater(car_params.steerRateCost, 1e-3) tuning = car_params.lateralTuning.which() if tuning == 'pid': self.assertTrue(len(car_params.lateralTuning.pid.kpV)) elif tuning == 'lqr': self.assertTrue(len(car_params.lateralTuning.lqr.a)) elif tuning == 'indi': self.assertGreater( car_params.lateralTuning.indi.outerLoopGain, 1e-3) # Run car interface CC = car.CarControl.new_message() for _ in range(10): car_interface.update(CC, []) car_interface.apply(CC) car_interface.apply(CC) CC = car.CarControl.new_message() CC.enabled = True for _ in range(10): car_interface.update(CC, []) car_interface.apply(CC) car_interface.apply(CC) # Test radar interface RadarInterface = importlib.import_module( 'selfdrive.car.%s.radar_interface' % car_params.carName).RadarInterface radar_interface = RadarInterface(car_params) assert radar_interface # Run radar interface once radar_interface.update([]) if hasattr(radar_interface, '_update') and hasattr( radar_interface, 'trigger_msg'): radar_interface._update([radar_interface.trigger_msg])
def fingerprint(logcan, sendcan, has_relay): params = Params() car_params = params.get("CarParams") if not travis: cached_fingerprint = params.get('CachedFingerprint') else: cached_fingerprint = None if car_params is not None: car_params = car.CarParams.from_bytes(car_params) fixed_fingerprint = os.environ.get('FINGERPRINT', "") skip_fw_query = os.environ.get('SKIP_FW_QUERY', False) if has_relay and not fixed_fingerprint and not skip_fw_query: # Vin query only reliably works thorugh OBDII bus = 1 cached_params = Params().get("CarParamsCache") if cached_params is not None: cached_params = car.CarParams.from_bytes(cached_params) if cached_params.carName == "mock": cached_params = None if cached_params is not None and len(cached_params.carFw) > 0 and cached_params.carVin is not VIN_UNKNOWN: cloudlog.warning("Using cached CarParams") vin = cached_params.carVin car_fw = list(cached_params.carFw) else: cloudlog.warning("Getting VIN & FW versions") _, vin = get_vin(logcan, sendcan, bus) car_fw = get_fw_versions(logcan, sendcan, bus) fw_candidates = match_fw_to_car(car_fw) else: vin = VIN_UNKNOWN fw_candidates, car_fw = set(), [] cloudlog.warning("VIN %s", vin) Params().put("CarVin", vin) finger = gen_empty_fingerprint() candidate_cars = {i: all_known_cars() for i in [0, 1]} # attempt fingerprint on both bus 0 and 1 frame = 0 frame_fingerprint = 10 # 0.1s car_fingerprint = None done = False if cached_fingerprint is not None and use_car_caching: # if we previously identified a car and fingerprint and user hasn't disabled caching cached_fingerprint = json.loads(cached_fingerprint) if cached_fingerprint[0] is None or len(cached_fingerprint) < 3: params.delete('CachedFingerprint') else: finger[0] = {int(key): value for key, value in cached_fingerprint[2].items()} source = car.CarParams.FingerprintSource.can return (str(cached_fingerprint[0]), finger, vin, car_fw, cached_fingerprint[1]) while not done: a = messaging.get_one_can(logcan) for can in a.can: # need to independently try to fingerprint both bus 0 and 1 to work # for the combo black_panda and honda_bosch. Ignore extended messages # and VIN query response. # Include bus 2 for toyotas to disambiguate cars using camera messages # (ideally should be done for all cars but we can't for Honda Bosch) if can.src in range(0, 4): finger[can.src][can.address] = len(can.dat) for b in candidate_cars: if (can.src == b or (only_toyota_left(candidate_cars[b]) and can.src == 2)) and \ can.address < 0x800 and can.address not in [0x7df, 0x7e0, 0x7e8]: candidate_cars[b] = eliminate_incompatible_cars(can, candidate_cars[b]) # if we only have one car choice and the time since we got our first # message has elapsed, exit for b in candidate_cars: # Toyota needs higher time to fingerprint, since DSU does not broadcast immediately if only_toyota_left(candidate_cars[b]): frame_fingerprint = 100 # 1s if len(candidate_cars[b]) == 1: if frame > frame_fingerprint: # fingerprint done car_fingerprint = candidate_cars[b][0] elif len(candidate_cars[b]) < 4: # For the RAV4 2019 and Corolla 2020 LE Fingerprint problem if frame > 180: if any(("TOYOTA COROLLA TSS2 2019" in c) for c in candidate_cars[b]): car_fingerprint = "TOYOTA COROLLA TSS2 2019" if any(("TOYOTA COROLLA HYBRID TSS2 2019" in c) for c in candidate_cars[b]): car_fingerprint = "TOYOTA COROLLA HYBRID TSS2 2019" if any(("HYUNDAI IONIQ ELECTRIC LIMITED 2019" in c) for c in candidate_cars[b]): car_fingerprint = "HYUNDAI IONIQ ELECTRIC LIMITED 2019" # bail if no cars left or we've been waiting for more than 2s failed = all(len(cc) == 0 for cc in candidate_cars.values()) or frame > 200 succeeded = car_fingerprint is not None done = failed or succeeded frame += 1 source = car.CarParams.FingerprintSource.can # If FW query returns exactly 1 candidate, use it if len(fw_candidates) == 1: car_fingerprint = list(fw_candidates)[0] source = car.CarParams.FingerprintSource.fw if fixed_fingerprint: car_fingerprint = fixed_fingerprint source = car.CarParams.FingerprintSource.fixed cloudlog.warning("fingerprinted %s", car_fingerprint) params.put("CachedFingerprint", json.dumps([car_fingerprint, source, {int(key): value for key, value in finger[0].items()}])) return car_fingerprint, finger, vin, car_fw, source
def fingerprint(logcan, sendcan, has_relay): params = Params() car_params = params.get("CarParams") if not travis: cached_fingerprint = params.get('CachedFingerprint') else: cached_fingerprint = None if car_params is not None: # use already stored VIN: a new VIN query cannot be done, since panda isn't in ELM327 mode car_params = car.CarParams.from_bytes(car_params) vin = VIN_UNKNOWN if car_params.carVin == "" else car_params.carVin elif has_relay: # Vin query only reliably works thorugh OBDII vin = get_vin(logcan, sendcan, 1) else: vin = VIN_UNKNOWN cloudlog.warning("VIN %s", vin) Params().put("CarVin", vin) finger = gen_empty_fingerprint() candidate_cars = {i: all_known_cars() for i in [0, 1] } # attempt fingerprint on both bus 0 and 1 frame = 0 frame_fingerprint = 10 # 0.1s car_fingerprint = None done = False if cached_fingerprint is not None and use_car_caching: # if we previously identified a car and fingerprint and user hasn't disabled caching cached_fingerprint = json.loads(cached_fingerprint) finger[0] = { key: value for key, value in cached_fingerprint[1].items() } return (str(cached_fingerprint[0]), finger, vin) while not done: a = get_one_can(logcan) for can in a.can: # need to independently try to fingerprint both bus 0 and 1 to work # for the combo black_panda and honda_bosch. Ignore extended messages # and VIN query response. # Include bus 2 for toyotas to disambiguate cars using camera messages # (ideally should be done for all cars but we can't for Honda Bosch) if can.src in range(0, 4): finger[can.src][can.address] = len(can.dat) for b in candidate_cars: if (can.src == b or (only_toyota_left(candidate_cars[b]) and can.src == 2)) and \ can.address < 0x800 and can.address not in [0x7df, 0x7e0, 0x7e8]: candidate_cars[b] = eliminate_incompatible_cars( can, candidate_cars[b]) # if we only have one car choice and the time since we got our first # message has elapsed, exit for b in candidate_cars: # Toyota needs higher time to fingerprint, since DSU does not broadcast immediately if only_toyota_left(candidate_cars[b]): frame_fingerprint = 100 # 1s if len(candidate_cars[b]) == 1: if frame > frame_fingerprint: # fingerprint done car_fingerprint = candidate_cars[b][0] # bail if no cars left or we've been waiting for more than 2s failed = all(len(cc) == 0 for cc in candidate_cars.values()) or frame > 200 succeeded = car_fingerprint is not None done = failed or succeeded frame += 1 cloudlog.warning("fingerprinted %s", car_fingerprint) params.put( "CachedFingerprint", json.dumps([ car_fingerprint, {int(key): value for key, value in finger[0].items()} ])) return car_fingerprint, finger, vin
# TODO: get updated routes for these cars ignore_can_valid = [ HYUNDAI.SANTA_FE, ] ignore_carstate_check = [ # TODO: chrysler gas state in panda also checks wheel speed, refactor so it's only gas CHRYSLER.PACIFICA_2017_HYBRID, ] @parameterized_class( ('car_model'), [(car, ) for i, car in enumerate(all_known_cars()) if i % NUM_JOBS == JOB_ID]) class TestCarModel(unittest.TestCase): @classmethod def setUpClass(cls): if cls.car_model not in ROUTES: # TODO: get routes for missing cars and remove this if cls.car_model in non_tested_cars: print(f"Skipping tests for {cls.car_model}: missing route") raise unittest.SkipTest else: raise Exception(f"missing test route for car {cls.car_model}") for seg in [2, 1, 0]: try: lr = LogReader(get_url(ROUTES[cls.car_model], seg)) break
class TestCarInterfaces(unittest.TestCase): @parameterized.expand([(car, ) for car in all_known_cars()]) def test_car_interfaces(self, car_name): if car_name in FINGERPRINTS: fingerprint = FINGERPRINTS[car_name][0] else: fingerprint = {} CarInterface, CarController, CarState = interfaces[car_name] fingerprints = { 0: fingerprint, 1: fingerprint, 2: fingerprint, } car_fw = [] car_params = CarInterface.get_params(car_name, fingerprints, car_fw) car_interface = CarInterface(car_params, CarController, CarState) assert car_params assert car_interface self.assertGreater(car_params.mass, 1) self.assertGreater(car_params.maxLateralAccel, 0) if car_params.steerControlType != car.CarParams.SteerControlType.angle: tuning = car_params.lateralTuning.which() if tuning == 'pid': self.assertTrue(len(car_params.lateralTuning.pid.kpV)) elif tuning == 'torque': kf = car_params.lateralTuning.torque.kf self.assertTrue(not math.isnan(kf) and kf > 0) self.assertTrue( not math.isnan(car_params.lateralTuning.torque.friction)) elif tuning == 'indi': self.assertTrue( len(car_params.lateralTuning.indi.outerLoopGainV)) # Run car interface CC = car.CarControl.new_message() for _ in range(10): car_interface.update(CC, []) car_interface.apply(CC) car_interface.apply(CC) CC = car.CarControl.new_message() CC.enabled = True for _ in range(10): car_interface.update(CC, []) car_interface.apply(CC) car_interface.apply(CC) # Test radar interface RadarInterface = importlib.import_module( f'selfdrive.car.{car_params.carName}.radar_interface' ).RadarInterface radar_interface = RadarInterface(car_params) assert radar_interface # Run radar interface once radar_interface.update([]) if not car_params.radarOffCan and radar_interface.rcp is not None and \ hasattr(radar_interface, '_update') and hasattr(radar_interface, 'trigger_msg'): radar_interface._update([radar_interface.trigger_msg])