Merge branch 'master' into mqb-long

# Conflicts:
#	panda
mqb-long
Jason Young 3 years ago
commit 7037350fbc
  1. 16
      .pre-commit-config.yaml
  2. 6
      Pipfile
  3. 1051
      Pipfile.lock
  4. 2
      cereal
  5. 2
      common/realtime.py
  6. 14
      mypy.ini
  7. 7
      selfdrive/car/ecu_addrs.py
  8. 3
      selfdrive/car/fw_versions.py
  9. 6
      selfdrive/car/gm/values.py
  10. 4
      selfdrive/car/honda/values.py
  11. 18
      selfdrive/car/hyundai/values.py
  12. 7
      selfdrive/car/isotp_parallel_query.py
  13. 13
      selfdrive/car/subaru/values.py
  14. 4
      selfdrive/car/toyota/values.py
  15. 17
      selfdrive/car/vin.py
  16. 5
      selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py
  17. 4
      selfdrive/controls/lib/longitudinal_planner.py
  18. 3
      selfdrive/controls/lib/radar_helpers.py
  19. 4
      selfdrive/debug/check_freq.py
  20. 4
      selfdrive/debug/check_timings.py
  21. 2
      selfdrive/sensord/tests/test_sensord.py
  22. 5
      selfdrive/test/longitudinal_maneuvers/plant.py
  23. 2
      selfdrive/test/process_replay/ref_commit
  24. 61
      selfdrive/test/process_replay/regen.py
  25. 30
      selfdrive/test/process_replay/test_processes.py
  26. 87
      system/camerad/test/test_camerad.py
  27. 1
      system/hardware/tici/casync.py

@ -24,18 +24,14 @@ repos:
# if you've got a short variable name that's getting flagged, add it here # if you've got a short variable name that's getting flagged, add it here
- -L bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup - -L bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup
- --builtins clear,rare,informal,usage,code,names,en-GB_to_en-US - --builtins clear,rare,informal,usage,code,names,en-GB_to_en-US
- repo: https://github.com/pre-commit/mirrors-mypy - repo: local
rev: v0.931
hooks: hooks:
- id: mypy - id: mypy
exclude: '^(pyextra/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(opendbc/)|(laika_repo/)|(rednose_repo/)/|(tinygrad/)|(tinygrad_repo/)' name: mypy
additional_dependencies: ['types-PyYAML', 'lxml', 'numpy', 'types-atomicwrites', 'types-pycurl', 'types-requests', 'types-certifi'] entry: mypy
args: language: system
- --warn-redundant-casts types: [python]
- --warn-return-any exclude: '^(pyextra/)|(cereal/)|(opendbc/)|(panda/)|(laika/)|(laika_repo/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(xx/)'
- --warn-unreachable
- --warn-unused-ignores
#- --html-report=/home/batman/openpilot
- repo: https://github.com/PyCQA/flake8 - repo: https://github.com/PyCQA/flake8
rev: 4.0.1 rev: 4.0.1
hooks: hooks:

@ -43,6 +43,12 @@ carla = {version = "==0.9.13", markers="platform_system != 'Darwin'"}
ft4222 = "*" ft4222 = "*"
pandas = "*" pandas = "*"
tabulate = "*" tabulate = "*"
types-pyyaml = "*"
lxml = "*"
types-atomicwrites = "*"
types-pycurl = "*"
types-requests = "*"
types-certifi = "*"
[packages] [packages]
atomicwrites = "*" atomicwrites = "*"

1051
Pipfile.lock generated

File diff suppressed because it is too large Load Diff

@ -1 +1 @@
Subproject commit a0c6f28d6bce2fd7d7ef2fd29e80d2eab118a6c6 Subproject commit e310f4860d349d2e260cfd4bb060b0705b17244c

@ -31,7 +31,7 @@ class Priority:
def set_realtime_priority(level: int) -> None: def set_realtime_priority(level: int) -> None:
if not PC: if not PC:
os.sched_setscheduler(0, os.SCHED_FIFO, os.sched_param(level)) # type: ignore[attr-defined] # pylint: disable=no-member os.sched_setscheduler(0, os.SCHED_FIFO, os.sched_param(level)) # pylint: disable=no-member
def set_core_affinity(cores: List[int]) -> None: def set_core_affinity(cores: List[int]) -> None:

@ -1,4 +1,16 @@
[mypy] [mypy]
python_version = 3.8 python_version = 3.8
ignore_missing_imports = True
plugins = numpy.typing.mypy_plugin plugins = numpy.typing.mypy_plugin
files = body, common, docs, scripts, selfdrive, site_scons, system, tools
exclude = ^(pyextra/)|(cereal/)|(opendbc/)|(panda/)|(laika/)|(laika_repo/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(xx/)
; third-party packages
ignore_missing_imports = True
; helpful warnings
warn_redundant_casts = True
warn_unreachable = True
warn_unused_ignores = True
; restrict dynamic typing
warn_return_any = True

@ -1,7 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import capnp import capnp
import time import time
import traceback
from typing import Optional, Set, Tuple from typing import Optional, Set, Tuple
import cereal.messaging as messaging import cereal.messaging as messaging
@ -62,7 +61,7 @@ def get_ecu_addrs(logcan: messaging.SubSocket, sendcan: messaging.PubSocket, que
print(f"Duplicate ECU address: {hex(msg.address)}") print(f"Duplicate ECU address: {hex(msg.address)}")
ecu_responses.add((msg.address, subaddr, msg.src)) ecu_responses.add((msg.address, subaddr, msg.src))
except Exception: except Exception:
cloudlog.warning(f"ECU addr scan exception: {traceback.format_exc()}") cloudlog.exception("ECU addr scan exception")
return ecu_responses return ecu_responses
@ -71,6 +70,8 @@ if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Get addresses of all ECUs') parser = argparse.ArgumentParser(description='Get addresses of all ECUs')
parser.add_argument('--debug', action='store_true') parser.add_argument('--debug', action='store_true')
parser.add_argument('--bus', type=int, default=1)
parser.add_argument('--timeout', type=float, default=1.0)
args = parser.parse_args() args = parser.parse_args()
logcan = messaging.sub_sock('can') logcan = messaging.sub_sock('can')
@ -79,7 +80,7 @@ if __name__ == "__main__":
time.sleep(1.0) time.sleep(1.0)
print("Getting ECU addresses ...") print("Getting ECU addresses ...")
ecu_addrs = get_all_ecu_addrs(logcan, sendcan, 1, debug=args.debug) ecu_addrs = get_all_ecu_addrs(logcan, sendcan, args.bus, args.timeout, debug=args.debug)
print() print()
print("Found ECUs on addresses:") print("Found ECUs on addresses:")

@ -1,5 +1,4 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import traceback
from collections import defaultdict from collections import defaultdict
from typing import Any, Optional, Set, Tuple from typing import Any, Optional, Set, Tuple
from tqdm import tqdm from tqdm import tqdm
@ -270,7 +269,7 @@ def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1,
car_fw.append(f) car_fw.append(f)
except Exception: except Exception:
cloudlog.warning(f"FW query exception: {traceback.format_exc()}") cloudlog.exception("FW query exception")
return car_fw return car_fw

@ -86,13 +86,13 @@ CAR_INFO: Dict[str, Union[GMCarInfo, List[GMCarInfo]]] = {
CAR.ACADIA: GMCarInfo("GMC Acadia 2018", video_link="https://www.youtube.com/watch?v=0ZN6DdsBUZo"), CAR.ACADIA: GMCarInfo("GMC Acadia 2018", video_link="https://www.youtube.com/watch?v=0ZN6DdsBUZo"),
CAR.BUICK_REGAL: GMCarInfo("Buick Regal Essence 2018"), CAR.BUICK_REGAL: GMCarInfo("Buick Regal Essence 2018"),
CAR.ESCALADE_ESV: GMCarInfo("Cadillac Escalade ESV 2016", "Adaptive Cruise Control (ACC) & LKAS"), CAR.ESCALADE_ESV: GMCarInfo("Cadillac Escalade ESV 2016", "Adaptive Cruise Control (ACC) & LKAS"),
CAR.BOLT_EV: GMCarInfo("Chevrolet Bolt EV 2022-23", "Adaptive Cruise Control (ACC)", footnotes=[], harness=Harness.gm), CAR.BOLT_EV: GMCarInfo("Chevrolet Bolt EV 2022-23", footnotes=[], harness=Harness.gm),
CAR.BOLT_EUV: GMCarInfo("Chevrolet Bolt EUV 2022-23", "Premier or Premier Redline Trim without Super Cruise Package", video_link="https://youtu.be/xvwzGMUA210", footnotes=[], harness=Harness.gm), CAR.BOLT_EUV: GMCarInfo("Chevrolet Bolt EUV 2022-23", "Premier or Premier Redline Trim without Super Cruise Package", "https://youtu.be/xvwzGMUA210", footnotes=[], harness=Harness.gm),
CAR.SILVERADO: [ CAR.SILVERADO: [
GMCarInfo("Chevrolet Silverado 1500 2020-21", "Safety Package II", footnotes=[], harness=Harness.gm), GMCarInfo("Chevrolet Silverado 1500 2020-21", "Safety Package II", footnotes=[], harness=Harness.gm),
GMCarInfo("GMC Sierra 1500 2020-21", "Driver Alert Package II", footnotes=[], harness=Harness.gm), GMCarInfo("GMC Sierra 1500 2020-21", "Driver Alert Package II", footnotes=[], harness=Harness.gm),
], ],
CAR.EQUINOX: GMCarInfo("Chevrolet Equinox 2019-22", "Adaptive Cruise Control (ACC)", footnotes=[], harness=Harness.gm), CAR.EQUINOX: GMCarInfo("Chevrolet Equinox 2019-22", footnotes=[], harness=Harness.gm),
} }

@ -110,13 +110,13 @@ class HondaCarInfo(CarInfo):
CAR_INFO: Dict[str, Optional[Union[HondaCarInfo, List[HondaCarInfo]]]] = { CAR_INFO: Dict[str, Optional[Union[HondaCarInfo, List[HondaCarInfo]]]] = {
CAR.ACCORD: [ CAR.ACCORD: [
HondaCarInfo("Honda Accord 2018-22", "All", video_link="https://www.youtube.com/watch?v=mrUwlj3Mi58", min_steer_speed=3. * CV.MPH_TO_MS, harness=Harness.bosch_a), HondaCarInfo("Honda Accord 2018-22", "All", "https://www.youtube.com/watch?v=mrUwlj3Mi58", min_steer_speed=3. * CV.MPH_TO_MS, harness=Harness.bosch_a),
HondaCarInfo("Honda Inspire 2018", "All", min_steer_speed=3. * CV.MPH_TO_MS, harness=Harness.bosch_a), HondaCarInfo("Honda Inspire 2018", "All", min_steer_speed=3. * CV.MPH_TO_MS, harness=Harness.bosch_a),
], ],
CAR.ACCORDH: HondaCarInfo("Honda Accord Hybrid 2018-22", "All", min_steer_speed=3. * CV.MPH_TO_MS, harness=Harness.bosch_a), CAR.ACCORDH: HondaCarInfo("Honda Accord Hybrid 2018-22", "All", min_steer_speed=3. * CV.MPH_TO_MS, harness=Harness.bosch_a),
CAR.CIVIC: HondaCarInfo("Honda Civic 2016-18", harness=Harness.nidec, video_link="https://youtu.be/-IkImTe1NYE"), CAR.CIVIC: HondaCarInfo("Honda Civic 2016-18", harness=Harness.nidec, video_link="https://youtu.be/-IkImTe1NYE"),
CAR.CIVIC_BOSCH: [ CAR.CIVIC_BOSCH: [
HondaCarInfo("Honda Civic 2019-21", "All", video_link="https://www.youtube.com/watch?v=4Iz1Mz5LGF8", footnotes=[Footnote.CIVIC_DIESEL], min_steer_speed=2. * CV.MPH_TO_MS, harness=Harness.bosch_a), HondaCarInfo("Honda Civic 2019-21", "All", "https://www.youtube.com/watch?v=4Iz1Mz5LGF8", [Footnote.CIVIC_DIESEL], min_steer_speed=2. * CV.MPH_TO_MS, harness=Harness.bosch_a),
HondaCarInfo("Honda Civic Hatchback 2017-21", harness=Harness.bosch_a), HondaCarInfo("Honda Civic Hatchback 2017-21", harness=Harness.bosch_a),
], ],
CAR.CIVIC_BOSCH_DIESEL: None, # same platform CAR.CIVIC_BOSCH_DIESEL: None, # same platform

@ -113,7 +113,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = {
CAR.ELANTRA_GT_I30: None, # dashcamOnly and same platform as CAR.ELANTRA CAR.ELANTRA_GT_I30: None, # dashcamOnly and same platform as CAR.ELANTRA
CAR.HYUNDAI_GENESIS: HyundaiCarInfo("Hyundai Genesis 2015-16", min_enable_speed=19 * CV.MPH_TO_MS, harness=Harness.hyundai_j), # TODO: check 2015 packages CAR.HYUNDAI_GENESIS: HyundaiCarInfo("Hyundai Genesis 2015-16", min_enable_speed=19 * CV.MPH_TO_MS, harness=Harness.hyundai_j), # TODO: check 2015 packages
CAR.IONIQ: HyundaiCarInfo("Hyundai Ioniq Hybrid 2017-19", harness=Harness.hyundai_c), CAR.IONIQ: HyundaiCarInfo("Hyundai Ioniq Hybrid 2017-19", harness=Harness.hyundai_c),
CAR.IONIQ_HEV_2022: HyundaiCarInfo("Hyundai Ioniq Hybrid 2020-22", "Smart Cruise Control (SCC)", harness=Harness.hyundai_h), # TODO: confirm 2020-21 harness CAR.IONIQ_HEV_2022: HyundaiCarInfo("Hyundai Ioniq Hybrid 2020-22", harness=Harness.hyundai_h), # TODO: confirm 2020-21 harness
CAR.IONIQ_EV_LTD: HyundaiCarInfo("Hyundai Ioniq Electric 2019", harness=Harness.hyundai_c), CAR.IONIQ_EV_LTD: HyundaiCarInfo("Hyundai Ioniq Electric 2019", harness=Harness.hyundai_c),
CAR.IONIQ_EV_2020: HyundaiCarInfo("Hyundai Ioniq Electric 2020", "All", harness=Harness.hyundai_h), CAR.IONIQ_EV_2020: HyundaiCarInfo("Hyundai Ioniq Electric 2020", "All", harness=Harness.hyundai_h),
CAR.IONIQ_PHEV_2019: HyundaiCarInfo("Hyundai Ioniq Plug-in Hybrid 2019", harness=Harness.hyundai_c), CAR.IONIQ_PHEV_2019: HyundaiCarInfo("Hyundai Ioniq Plug-in Hybrid 2019", harness=Harness.hyundai_c),
@ -123,17 +123,17 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = {
CAR.KONA_EV_2022: HyundaiCarInfo("Hyundai Kona Electric 2022", harness=Harness.hyundai_o), CAR.KONA_EV_2022: HyundaiCarInfo("Hyundai Kona Electric 2022", harness=Harness.hyundai_o),
CAR.KONA_HEV: HyundaiCarInfo("Hyundai Kona Hybrid 2020", video_link="https://youtu.be/0dwpAHiZgFo", harness=Harness.hyundai_i), # TODO: check packages CAR.KONA_HEV: HyundaiCarInfo("Hyundai Kona Hybrid 2020", video_link="https://youtu.be/0dwpAHiZgFo", harness=Harness.hyundai_i), # TODO: check packages
CAR.SANTA_FE: HyundaiCarInfo("Hyundai Santa Fe 2019-20", "All", harness=Harness.hyundai_d), CAR.SANTA_FE: HyundaiCarInfo("Hyundai Santa Fe 2019-20", "All", harness=Harness.hyundai_d),
CAR.SANTA_FE_2022: HyundaiCarInfo("Hyundai Santa Fe 2021-22", "All", video_link="https://youtu.be/VnHzSTygTS4", harness=Harness.hyundai_l), CAR.SANTA_FE_2022: HyundaiCarInfo("Hyundai Santa Fe 2021-22", "All", "https://youtu.be/VnHzSTygTS4", harness=Harness.hyundai_l),
CAR.SANTA_FE_HEV_2022: HyundaiCarInfo("Hyundai Santa Fe Hybrid 2022", "All", harness=Harness.hyundai_l), CAR.SANTA_FE_HEV_2022: HyundaiCarInfo("Hyundai Santa Fe Hybrid 2022", "All", harness=Harness.hyundai_l),
CAR.SANTA_FE_PHEV_2022: HyundaiCarInfo("Hyundai Santa Fe Plug-in Hybrid 2022", "All", harness=Harness.hyundai_l), CAR.SANTA_FE_PHEV_2022: HyundaiCarInfo("Hyundai Santa Fe Plug-in Hybrid 2022", "All", harness=Harness.hyundai_l),
CAR.SONATA: HyundaiCarInfo("Hyundai Sonata 2020-22", "All", video_link="https://www.youtube.com/watch?v=ix63r9kE3Fw", harness=Harness.hyundai_a), CAR.SONATA: HyundaiCarInfo("Hyundai Sonata 2020-22", "All", "https://www.youtube.com/watch?v=ix63r9kE3Fw", harness=Harness.hyundai_a),
CAR.SONATA_LF: HyundaiCarInfo("Hyundai Sonata 2018-19", harness=Harness.hyundai_e), CAR.SONATA_LF: HyundaiCarInfo("Hyundai Sonata 2018-19", harness=Harness.hyundai_e),
CAR.TUCSON: [ CAR.TUCSON: [
HyundaiCarInfo("Hyundai Tucson 2021", min_enable_speed=19 * CV.MPH_TO_MS, harness=Harness.hyundai_l), HyundaiCarInfo("Hyundai Tucson 2021", min_enable_speed=19 * CV.MPH_TO_MS, harness=Harness.hyundai_l),
HyundaiCarInfo("Hyundai Tucson Diesel 2019", harness=Harness.hyundai_l), HyundaiCarInfo("Hyundai Tucson Diesel 2019", harness=Harness.hyundai_l),
], ],
CAR.PALISADE: [ CAR.PALISADE: [
HyundaiCarInfo("Hyundai Palisade 2020-22", "All", video_link="https://youtu.be/TAnDqjF4fDY?t=456", harness=Harness.hyundai_h), HyundaiCarInfo("Hyundai Palisade 2020-22", "All", "https://youtu.be/TAnDqjF4fDY?t=456", harness=Harness.hyundai_h),
HyundaiCarInfo("Kia Telluride 2020", "All", harness=Harness.hyundai_h), HyundaiCarInfo("Kia Telluride 2020", "All", harness=Harness.hyundai_h),
], ],
CAR.VELOSTER: HyundaiCarInfo("Hyundai Veloster 2019-20", min_enable_speed=5. * CV.MPH_TO_MS, harness=Harness.hyundai_e), CAR.VELOSTER: HyundaiCarInfo("Hyundai Veloster 2019-20", min_enable_speed=5. * CV.MPH_TO_MS, harness=Harness.hyundai_e),
@ -145,10 +145,10 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = {
CAR.KIA_FORTE: HyundaiCarInfo("Kia Forte 2019-21", harness=Harness.hyundai_g), CAR.KIA_FORTE: HyundaiCarInfo("Kia Forte 2019-21", harness=Harness.hyundai_g),
CAR.KIA_K5_2021: HyundaiCarInfo("Kia K5 2021-22", harness=Harness.hyundai_a), CAR.KIA_K5_2021: HyundaiCarInfo("Kia K5 2021-22", harness=Harness.hyundai_a),
CAR.KIA_NIRO_EV: [ CAR.KIA_NIRO_EV: [
HyundaiCarInfo("Kia Niro EV 2019", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_h), HyundaiCarInfo("Kia Niro EV 2019", "All", "https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_h),
HyundaiCarInfo("Kia Niro EV 2020", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_f), HyundaiCarInfo("Kia Niro EV 2020", "All", "https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_f),
HyundaiCarInfo("Kia Niro EV 2021", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_c), HyundaiCarInfo("Kia Niro EV 2021", "All", "https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_c),
HyundaiCarInfo("Kia Niro EV 2022", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_h), HyundaiCarInfo("Kia Niro EV 2022", "All", "https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_h),
], ],
CAR.KIA_NIRO_PHEV: HyundaiCarInfo("Kia Niro Plug-in Hybrid 2018-19", "All", min_enable_speed=10. * CV.MPH_TO_MS, harness=Harness.hyundai_c), CAR.KIA_NIRO_PHEV: HyundaiCarInfo("Kia Niro Plug-in Hybrid 2018-19", "All", min_enable_speed=10. * CV.MPH_TO_MS, harness=Harness.hyundai_c),
CAR.KIA_NIRO_HEV_2021: [ CAR.KIA_NIRO_HEV_2021: [
@ -163,7 +163,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = {
], ],
CAR.KIA_SELTOS: HyundaiCarInfo("Kia Seltos 2021", harness=Harness.hyundai_a), CAR.KIA_SELTOS: HyundaiCarInfo("Kia Seltos 2021", harness=Harness.hyundai_a),
CAR.KIA_SORENTO: [ CAR.KIA_SORENTO: [
HyundaiCarInfo("Kia Sorento 2018", "Advanced Smart Cruise Control", video_link="https://www.youtube.com/watch?v=Fkh3s6WHJz8", harness=Harness.hyundai_c), HyundaiCarInfo("Kia Sorento 2018", "Advanced Smart Cruise Control", "https://www.youtube.com/watch?v=Fkh3s6WHJz8", harness=Harness.hyundai_c),
HyundaiCarInfo("Kia Sorento 2019", video_link="https://www.youtube.com/watch?v=Fkh3s6WHJz8", harness=Harness.hyundai_e), HyundaiCarInfo("Kia Sorento 2019", video_link="https://www.youtube.com/watch?v=Fkh3s6WHJz8", harness=Harness.hyundai_e),
], ],
CAR.KIA_STINGER: HyundaiCarInfo("Kia Stinger 2018-20", video_link="https://www.youtube.com/watch?v=MJ94qoofYw0", harness=Harness.hyundai_c), CAR.KIA_STINGER: HyundaiCarInfo("Kia Stinger 2018-20", video_link="https://www.youtube.com/watch?v=MJ94qoofYw0", harness=Harness.hyundai_c),

@ -1,7 +1,6 @@
import time import time
from collections import defaultdict from collections import defaultdict
from functools import partial from functools import partial
from typing import Optional
import cereal.messaging as messaging import cereal.messaging as messaging
from system.swaglog import cloudlog from system.swaglog import cloudlog
@ -107,12 +106,15 @@ class IsoTpParallelQuery:
for tx_addr, msg in msgs.items(): for tx_addr, msg in msgs.items():
try: try:
dat: Optional[bytes] = msg.recv() dat, updated = msg.recv()
except Exception: except Exception:
cloudlog.exception(f"Error processing UDS response: {tx_addr}") cloudlog.exception(f"Error processing UDS response: {tx_addr}")
request_done[tx_addr] = True request_done[tx_addr] = True
continue continue
if updated:
response_timeouts[tx_addr] = time.monotonic() + timeout
if not dat: if not dat:
continue continue
@ -121,7 +123,6 @@ class IsoTpParallelQuery:
response_valid = dat[:len(expected_response)] == expected_response response_valid = dat[:len(expected_response)] == expected_response
if response_valid: if response_valid:
response_timeouts[tx_addr] = time.monotonic() + timeout
if counter + 1 < len(self.request): if counter + 1 < len(self.request):
msg.send(self.request[counter + 1]) msg.send(self.request[counter + 1])
request_counter[tx_addr] += 1 request_counter[tx_addr] += 1

@ -124,23 +124,26 @@ FW_VERSIONS = {
CAR.LEGACY: { CAR.LEGACY: {
(Ecu.abs, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'\xa1\\ x04\x01', b'\xa1\\ x04\x01',
b'\xa1 \x03\x03' b'\xa1 \x03\x03',
b'\xa1 \x02\x01',
], ],
(Ecu.eps, 0x746, None): [ (Ecu.eps, 0x746, None): [
b'\x9b\xc0\x11\x00', b'\x9b\xc0\x11\x00',
b'\x9b\xc0\x11\x02' b'\x9b\xc0\x11\x02',
], ],
(Ecu.fwdCamera, 0x787, None): [ (Ecu.fwdCamera, 0x787, None): [
b'\x00\x00e\x80\x00\x1f@ \x19\x00', b'\x00\x00e\x80\x00\x1f@ \x19\x00',
b'\x00\x00e\x9a\x00\x00\x00\x00\x00\x00' b'\x00\x00e\x9a\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.engine, 0x7e0, None): [ (Ecu.engine, 0x7e0, None): [
b'\xde\"a0\x07', b'\xde\"a0\x07',
b'\xe2"aq\x07' b'\xe2"aq\x07',
b'\xde,\xa0@\x07',
], ],
(Ecu.transmission, 0x7e1, None): [ (Ecu.transmission, 0x7e1, None): [
b'\xa5\xf6\x05@\x00', b'\xa5\xf6\x05@\x00',
b'\xa7\xf6\x04@\x00' b'\xa7\xf6\x04@\x00',
b'\xa5\xfe\xc7@\x00',
], ],
}, },
CAR.IMPREZA: { CAR.IMPREZA: {

@ -136,7 +136,7 @@ CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = {
CAR.HIGHLANDERH: ToyotaCarInfo("Toyota Highlander Hybrid 2017-19", footnotes=[Footnote.DSU]), CAR.HIGHLANDERH: ToyotaCarInfo("Toyota Highlander Hybrid 2017-19", footnotes=[Footnote.DSU]),
CAR.HIGHLANDERH_TSS2: ToyotaCarInfo("Toyota Highlander Hybrid 2020-22"), CAR.HIGHLANDERH_TSS2: ToyotaCarInfo("Toyota Highlander Hybrid 2020-22"),
CAR.PRIUS: [ CAR.PRIUS: [
ToyotaCarInfo("Toyota Prius 2016", "Toyota Safety Sense P", video_link="https://www.youtube.com/watch?v=8zopPJI8XQ0", footnotes=[Footnote.DSU]), ToyotaCarInfo("Toyota Prius 2016", "Toyota Safety Sense P", "https://www.youtube.com/watch?v=8zopPJI8XQ0", [Footnote.DSU]),
ToyotaCarInfo("Toyota Prius 2017-20", video_link="https://www.youtube.com/watch?v=8zopPJI8XQ0", footnotes=[Footnote.DSU]), ToyotaCarInfo("Toyota Prius 2017-20", video_link="https://www.youtube.com/watch?v=8zopPJI8XQ0", footnotes=[Footnote.DSU]),
ToyotaCarInfo("Toyota Prius Prime 2017-20", video_link="https://www.youtube.com/watch?v=8zopPJI8XQ0", footnotes=[Footnote.DSU]), ToyotaCarInfo("Toyota Prius Prime 2017-20", video_link="https://www.youtube.com/watch?v=8zopPJI8XQ0", footnotes=[Footnote.DSU]),
], ],
@ -150,7 +150,7 @@ CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = {
ToyotaCarInfo("Toyota RAV4 2017-18", footnotes=[Footnote.DSU]) ToyotaCarInfo("Toyota RAV4 2017-18", footnotes=[Footnote.DSU])
], ],
CAR.RAV4H: [ CAR.RAV4H: [
ToyotaCarInfo("Toyota RAV4 Hybrid 2016", "Toyota Safety Sense P", video_link="https://youtu.be/LhT5VzJVfNI?t=26", footnotes=[Footnote.DSU]), ToyotaCarInfo("Toyota RAV4 Hybrid 2016", "Toyota Safety Sense P", "https://youtu.be/LhT5VzJVfNI?t=26", [Footnote.DSU]),
ToyotaCarInfo("Toyota RAV4 Hybrid 2017-18", video_link="https://youtu.be/LhT5VzJVfNI?t=26", footnotes=[Footnote.DSU]) ToyotaCarInfo("Toyota RAV4 Hybrid 2017-18", video_link="https://youtu.be/LhT5VzJVfNI?t=26", footnotes=[Footnote.DSU])
], ],
CAR.RAV4_TSS2: ToyotaCarInfo("Toyota RAV4 2019-21", video_link="https://www.youtube.com/watch?v=wJxjDd42gGA"), CAR.RAV4_TSS2: ToyotaCarInfo("Toyota RAV4 2019-21", video_link="https://www.youtube.com/watch?v=wJxjDd42gGA"),

@ -1,6 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import re import re
import traceback
import cereal.messaging as messaging import cereal.messaging as messaging
from selfdrive.car.isotp_parallel_query import IsoTpParallelQuery from selfdrive.car.isotp_parallel_query import IsoTpParallelQuery
@ -28,17 +27,27 @@ def get_vin(logcan, sendcan, bus, timeout=0.1, retry=5, debug=False):
vin = vin[1:18] vin = vin[1:18]
return addr[0], rx_addr, vin.decode() return addr[0], rx_addr, vin.decode()
print(f"vin query retry ({i+1}) ...") cloudlog.error(f"vin query retry ({i+1}) ...")
except Exception: except Exception:
cloudlog.warning(f"VIN query exception: {traceback.format_exc()}") cloudlog.exception("VIN query exception")
return 0, 0, VIN_UNKNOWN return 0, 0, VIN_UNKNOWN
if __name__ == "__main__": if __name__ == "__main__":
import argparse
import time import time
parser = argparse.ArgumentParser(description='Get VIN of the car')
parser.add_argument('--debug', action='store_true')
parser.add_argument('--bus', type=int, default=1)
parser.add_argument('--timeout', type=float, default=0.1)
parser.add_argument('--retry', type=int, default=5)
args = parser.parse_args()
sendcan = messaging.pub_sock('sendcan') sendcan = messaging.pub_sock('sendcan')
logcan = messaging.sub_sock('can') logcan = messaging.sub_sock('can')
time.sleep(1) time.sleep(1)
addr, vin_rx_addr, vin = get_vin(logcan, sendcan, 1, debug=False)
addr, vin_rx_addr, vin = get_vin(logcan, sendcan, args.bus, args.timeout, args.retry, debug=args.debug)
print(f'TX: {hex(addr)}, RX: {hex(vin_rx_addr)}, VIN: {vin}') print(f'TX: {hex(addr)}, RX: {hex(vin_rx_addr)}, VIN: {vin}')

@ -320,7 +320,7 @@ class LongitudinalMpc:
# Update in ACC mode or ACC/e2e blend # Update in ACC mode or ACC/e2e blend
if self.mode == 'acc': if self.mode == 'acc':
self.params[:,0] = MIN_ACCEL if self.status else self.cruise_min_a self.params[:,0] = MIN_ACCEL
self.params[:,1] = self.cruise_max_a self.params[:,1] = self.cruise_max_a
self.params[:,5] = LEAD_DANGER_FACTOR self.params[:,5] = LEAD_DANGER_FACTOR
@ -341,11 +341,12 @@ class LongitudinalMpc:
elif self.mode == 'blended': elif self.mode == 'blended':
self.params[:,0] = MIN_ACCEL self.params[:,0] = MIN_ACCEL
self.params[:,1] = MAX_ACCEL self.params[:,1] = MAX_ACCEL
self.params[:,5] = 1.0 self.params[:,5] = 1.0
x_obstacles = np.column_stack([lead_0_obstacle, x_obstacles = np.column_stack([lead_0_obstacle,
lead_1_obstacle]) lead_1_obstacle])
cruise_target = T_IDXS * v_cruise + x[0] cruise_target = T_IDXS * np.clip(v_cruise, v_ego - 2.0, 1e3) + x[0]
xforward = ((v[1:] + v[:-1]) / 2) * (T_IDXS[1:] - T_IDXS[:-1]) xforward = ((v[1:] + v[:-1]) / 2) * (T_IDXS[1:] - T_IDXS[:-1])
x = np.cumsum(np.insert(xforward, 0, x[0])) x = np.cumsum(np.insert(xforward, 0, x[0]))

@ -18,8 +18,8 @@ from system.swaglog import cloudlog
LON_MPC_STEP = 0.2 # first step is 0.2s LON_MPC_STEP = 0.2 # first step is 0.2s
AWARENESS_DECEL = -0.2 # car smoothly decel at .2m/s^2 when user is distracted AWARENESS_DECEL = -0.2 # car smoothly decel at .2m/s^2 when user is distracted
A_CRUISE_MIN = -1.2 A_CRUISE_MIN = -1.2
A_CRUISE_MAX_VALS = [1.2, 1.2, 0.8, 0.6] A_CRUISE_MAX_VALS = [1.6, 1.2, 0.8, 0.6]
A_CRUISE_MAX_BP = [0., 15., 25., 40.] A_CRUISE_MAX_BP = [0., 10.0, 25., 40.]
# Lookup table for turns # Lookup table for turns
_A_TOTAL_MAX_V = [1.7, 3.2] _A_TOTAL_MAX_V = [1.7, 3.2]

@ -2,8 +2,7 @@ from common.numpy_fast import mean
from common.kalman.simple_kalman import KF1D from common.kalman.simple_kalman import KF1D
# the longer lead decels, the more likely it will keep decelerating # Default lead acceleration decay set to 50% at 1s
# TODO is this a good default?
_LEAD_ACCEL_TAU = 1.5 _LEAD_ACCEL_TAU = 1.5
# radar tracks # radar tracks

@ -2,7 +2,7 @@
import argparse import argparse
import numpy as np import numpy as np
from collections import defaultdict, deque from collections import defaultdict, deque
from typing import DefaultDict, Deque from typing import DefaultDict, Deque, MutableSequence
from common.realtime import sec_since_boot from common.realtime import sec_since_boot
import cereal.messaging as messaging import cereal.messaging as messaging
@ -19,7 +19,7 @@ if __name__ == "__main__":
socket_names = args.socket socket_names = args.socket
sockets = {} sockets = {}
rcv_times: DefaultDict[str, Deque[float]] = defaultdict(lambda: deque(maxlen=100)) rcv_times: DefaultDict[str, MutableSequence[float]] = defaultdict(lambda: deque(maxlen=100))
valids: DefaultDict[str, Deque[bool]] = defaultdict(lambda: deque(maxlen=100)) valids: DefaultDict[str, Deque[bool]] = defaultdict(lambda: deque(maxlen=100))
t = sec_since_boot() t = sec_since_boot()

@ -3,13 +3,13 @@
import sys import sys
import time import time
import numpy as np import numpy as np
from typing import DefaultDict, Deque from typing import DefaultDict, MutableSequence
from collections import defaultdict, deque from collections import defaultdict, deque
import cereal.messaging as messaging import cereal.messaging as messaging
socks = {s: messaging.sub_sock(s, conflate=False) for s in sys.argv[1:]} socks = {s: messaging.sub_sock(s, conflate=False) for s in sys.argv[1:]}
ts: DefaultDict[str, Deque[float]] = defaultdict(lambda: deque(maxlen=100)) ts: DefaultDict[str, MutableSequence[float]] = defaultdict(lambda: deque(maxlen=100))
if __name__ == "__main__": if __name__ == "__main__":
while True: while True:

@ -51,7 +51,7 @@ Sensor = log.SensorEventData.SensorSource
SensorConfig = namedtuple('SensorConfig', ['type', 'sanity_min', 'sanity_max']) SensorConfig = namedtuple('SensorConfig', ['type', 'sanity_min', 'sanity_max'])
ALL_SENSORS = { ALL_SENSORS = {
Sensor.rpr0521: { Sensor.rpr0521: {
SensorConfig("light", 0, 150), SensorConfig("light", 0, 1023),
}, },
Sensor.lsm6ds3: { Sensor.lsm6ds3: {

@ -8,7 +8,7 @@ from common.realtime import Ratekeeper, DT_MDL
from selfdrive.controls.lib.longcontrol import LongCtrlState from selfdrive.controls.lib.longcontrol import LongCtrlState
from selfdrive.modeld.constants import T_IDXS from selfdrive.modeld.constants import T_IDXS
from selfdrive.controls.lib.longitudinal_planner import LongitudinalPlanner from selfdrive.controls.lib.longitudinal_planner import LongitudinalPlanner
from selfdrive.controls.lib.radar_helpers import _LEAD_ACCEL_TAU
class Plant(): class Plant():
messaging_initialized = False messaging_initialized = False
@ -83,7 +83,8 @@ class Plant():
lead.vLead = float(v_lead) lead.vLead = float(v_lead)
lead.vLeadK = float(v_lead) lead.vLeadK = float(v_lead)
lead.aLeadK = float(a_lead) lead.aLeadK = float(a_lead)
lead.aLeadTau = float(1.5) # TODO use real radard logic for this
lead.aLeadTau = float(_LEAD_ACCEL_TAU)
lead.status = status lead.status = status
lead.modelProb = float(prob) lead.modelProb = float(prob)
if not self.only_lead2: if not self.only_lead2:

@ -1 +1 @@
051fa5bea42027c1a756ae61fd0c752c1e911899 9098c1cf6993598071c3e27448356eef86660d02

@ -106,6 +106,23 @@ def replay_sensor_events(s, msgs):
rk.keep_time() rk.keep_time()
def replay_sensor_event(s, msgs):
smsgs = [m for m in msgs if m.which() == s]
#if len(smsgs) == 0:
# return
pm = messaging.PubMaster([s, ])
rk = Ratekeeper(service_list[s].frequency, print_delay_threshold=None)
while True:
for m in smsgs:
m = m.as_builder()
m.logMonoTime = int(sec_since_boot() * 1e9)
getattr(m, m.which()).timestamp = m.logMonoTime
pm.send(m.which(), m)
rk.keep_time()
def replay_service(s, msgs): def replay_service(s, msgs):
pm = messaging.PubMaster([s, ]) pm = messaging.PubMaster([s, ])
rk = Ratekeeper(service_list[s].frequency, print_delay_threshold=None) rk = Ratekeeper(service_list[s].frequency, print_delay_threshold=None)
@ -193,8 +210,49 @@ def migrate_carparams(lr):
return all_msgs return all_msgs
def migrate_sensorEvents(lr):
all_msgs = []
for msg in lr:
if msg.which() != 'sensorEvents':
all_msgs.append(msg)
continue
# migrate to split sensor events
for evt in msg.sensorEvents:
# build new message for each sensor type
sensor_service = ''
if evt.which() == 'acceleration':
sensor_service = 'accelerometer'
elif evt.which() == 'gyro' or evt.which() == 'gyroUncalibrated':
sensor_service = 'gyroscope'
elif evt.which() == 'light' or evt.which() == 'proximity':
sensor_service = 'lightSensor'
elif evt.which() == 'magnetic' or evt.which() == 'magneticUncalibrated':
sensor_service = 'magnetometer'
elif evt.which() == 'temperature':
sensor_service = 'temperatureSensor'
m = messaging.new_message(sensor_service)
m.valid = True
m_dat = getattr(m, sensor_service)
m_dat.version = evt.version
m_dat.sensor = evt.sensor
m_dat.type = evt.type
m_dat.source = evt.source
setattr(m_dat, evt.which(), getattr(evt, evt.which()))
all_msgs.append(m.as_reader())
# append also legacy sensorEvents, to have both (remove later)
all_msgs.append(msg)
return all_msgs
def regen_segment(lr, frs=None, outdir=FAKEDATA, disable_tqdm=False): def regen_segment(lr, frs=None, outdir=FAKEDATA, disable_tqdm=False):
lr = migrate_carparams(list(lr)) lr = migrate_carparams(list(lr))
lr = migrate_sensorEvents(list(lr))
if frs is None: if frs is None:
frs = dict() frs = dict()
@ -213,6 +271,9 @@ def regen_segment(lr, frs=None, outdir=FAKEDATA, disable_tqdm=False):
fake_daemons = { fake_daemons = {
'sensord': [ 'sensord': [
multiprocessing.Process(target=replay_sensor_events, args=('sensorEvents', lr)), multiprocessing.Process(target=replay_sensor_events, args=('sensorEvents', lr)),
multiprocessing.Process(target=replay_sensor_event, args=('accelerometer', lr)),
multiprocessing.Process(target=replay_sensor_event, args=('gyroscope', lr)),
multiprocessing.Process(target=replay_sensor_event, args=('magnetometer', lr)),
], ],
'pandad': [ 'pandad': [
multiprocessing.Process(target=replay_service, args=('can', lr)), multiprocessing.Process(target=replay_service, args=('can', lr)),

@ -38,21 +38,21 @@ source_segments = [
] ]
segments = [ segments = [
("BODY", "regen9D38397D30D|2022-09-09--13-12-48--0"), ("BODY", "regenFA002A80700|2022-09-27--15-37-02--0"),
("HYUNDAI", "regenB3953B393C0|2022-09-09--14-49-37--0"), ("HYUNDAI", "regenBE53A59065B|2022-09-27--16-52-03--0"),
("HYUNDAI", "regen8DB830E5376|2022-09-13--17-24-37--0"), ("HYUNDAI", "regen11AA43BCA5F|2022-09-27--15-39-54--0"),
("TOYOTA", "regen8FCBB6F06F1|2022-09-09--13-14-07--0"), ("TOYOTA", "regen929C5790007|2022-09-27--16-27-47--0"),
("TOYOTA2", "regen956BFA75300|2022-09-09--14-51-24--0"), ("TOYOTA2", "regenEA3950D7F22|2022-09-27--15-43-24--0"),
("TOYOTA3", "regenE909BC2F430|2022-09-09--20-44-49--0"), ("TOYOTA3", "regen89026F6BD8D|2022-09-27--15-45-37--0"),
("HONDA", "regenD1D10209015|2022-09-09--14-53-09--0"), ("HONDA", "regenC7D5645EB17|2022-09-27--15-47-29--0"),
("HONDA2", "regen3F7C2EFDC08|2022-09-09--19-41-19--0"), ("HONDA2", "regenCC2ECCE5742|2022-09-27--16-18-01--0"),
("CHRYSLER", "regen92783EAE66B|2022-09-09--13-15-44--0"), ("CHRYSLER", "regenC253C4DAC90|2022-09-27--15-51-03--0"),
("RAM", "regenBE5DAAEF30F|2022-09-13--17-06-24--0"), ("RAM", "regen20490083AE7|2022-09-27--15-53-15--0"),
("SUBARU", "regen8A363AF7E14|2022-09-13--17-20-39--0"), ("SUBARU", "regen1E72BBDCED5|2022-09-27--15-55-31--0"),
("GM", "regen31EA3F9A37C|2022-09-09--21-06-36--0"), ("GM", "regen45B05A80EF6|2022-09-27--15-57-22--0"),
("NISSAN", "regenAA21ADE5921|2022-09-09--19-44-37--0"), ("NISSAN", "regenC19D899B46D|2022-09-27--15-59-13--0"),
("VOLKSWAGEN", "regenA1BF4D17761|2022-09-09--19-46-24--0"), ("VOLKSWAGEN", "regenD8F7AC4BD0D|2022-09-27--16-41-45--0"),
("MAZDA", "regen1994C97E977|2022-09-13--16-34-44--0"), ("MAZDA", "regenFC3F9ECBB64|2022-09-27--16-03-09--0"),
] ]
# dashcamOnly makes don't need to be tested until a full port is done # dashcamOnly makes don't need to be tested until a full port is done

@ -1,25 +1,18 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import time import time
import unittest import unittest
from collections import defaultdict
import cereal.messaging as messaging import cereal.messaging as messaging
from cereal.services import service_list
from selfdrive.manager.process_config import managed_processes
from system.hardware import TICI from system.hardware import TICI
from selfdrive.test.helpers import with_processes
TEST_TIMESPAN = 30 # random.randint(60, 180) # seconds TEST_TIMESPAN = 30
SKIP_FRAME_TOLERANCE = 0 LAG_FRAME_TOLERANCE = 0.5 # ms
LAG_FRAME_TOLERANCE = 2 # ms
FPS_BASELINE = 20 CAMERAS = ('roadCameraState', 'driverCameraState', 'wideRoadCameraState')
CAMERAS = {
"roadCameraState": FPS_BASELINE,
"driverCameraState": FPS_BASELINE // 2,
}
if TICI:
CAMERAS["driverCameraState"] = FPS_BASELINE
CAMERAS["wideRoadCameraState"] = FPS_BASELINE
class TestCamerad(unittest.TestCase): class TestCamerad(unittest.TestCase):
@classmethod @classmethod
@ -27,37 +20,57 @@ class TestCamerad(unittest.TestCase):
if not TICI: if not TICI:
raise unittest.SkipTest raise unittest.SkipTest
@with_processes(['camerad']) # run camerad and record logs
def test_frame_packets(self): managed_processes['camerad'].start()
print("checking frame pkts continuity") time.sleep(3)
print(TEST_TIMESPAN) socks = {c: messaging.sub_sock(c, conflate=False, timeout=100) for c in CAMERAS}
cls.logs = defaultdict(list)
start_time = time.monotonic()
while time.monotonic()- start_time < TEST_TIMESPAN:
for cam, s in socks.items():
cls.logs[cam] += messaging.drain_sock(s)
time.sleep(0.2)
managed_processes['camerad'].stop()
sm = messaging.SubMaster([socket_name for socket_name in CAMERAS]) cls.log_by_frame_id = defaultdict(list)
for cam, msgs in cls.logs.items():
expected_frames = service_list[cam].frequency * TEST_TIMESPAN
assert expected_frames*0.95 < len(msgs) < expected_frames*1.05, f"unexpected frame count {cam}: {expected_frames=}, got {len(msgs)}"
last_frame_id = dict.fromkeys(CAMERAS, None) for m in msgs:
last_ts = dict.fromkeys(CAMERAS, None) cls.log_by_frame_id[getattr(m, m.which()).frameId].append(m)
start_time_sec = time.time()
while time.time()- start_time_sec < TEST_TIMESPAN:
sm.update()
for camera in CAMERAS: # strip beginning and end
if sm.updated[camera]: for _ in range(3):
ct = (sm[camera].timestampEof if not TICI else sm[camera].timestampSof) / 1e6 mn, mx = min(cls.log_by_frame_id.keys()), max(cls.log_by_frame_id.keys())
if last_frame_id[camera] is None: del cls.log_by_frame_id[mn]
last_frame_id[camera] = sm[camera].frameId del cls.log_by_frame_id[mx]
last_ts[camera] = ct
continue @classmethod
def tearDownClass(cls):
managed_processes['camerad'].stop()
dfid = sm[camera].frameId - last_frame_id[camera] def test_frame_skips(self):
self.assertTrue(abs(dfid - 1) <= SKIP_FRAME_TOLERANCE, "%s frame id diff is %d" % (camera, dfid)) skips = {}
frame_ids = self.log_by_frame_id.keys()
for frame_id in range(min(frame_ids), max(frame_ids)):
seen_cams = [msg.which() for msg in self.log_by_frame_id[frame_id]]
skip_cams = set(CAMERAS) - set(seen_cams)
if len(skip_cams):
skips[frame_id] = skip_cams
assert len(skips) == 0, f"Found frame skips, missing cameras for the following frames: {skips}"
dts = ct - last_ts[camera] def test_frame_sync(self):
self.assertTrue(abs(dts - (1000/CAMERAS[camera])) < LAG_FRAME_TOLERANCE, f"{camera} frame t(ms) diff is {dts:f}") frame_times = {frame_id: [getattr(m, m.which()).timestampSof for m in msgs] for frame_id, msgs in self.log_by_frame_id.items()}
diffs = {frame_id: (max(ts) - min(ts))/1e6 for frame_id, ts in frame_times.items()}
last_frame_id[camera] = sm[camera].frameId
last_ts[camera] = ct
time.sleep(0.01) def get_desc(fid, diff):
cam_times = [(m.which(), getattr(m, m.which()).timestampSof/1e6) for m in self.log_by_frame_id[fid]]
return f"{diff=} {cam_times=}"
laggy_frames = {k: get_desc(k, v) for k, v in diffs.items() if v > LAG_FRAME_TOLERANCE}
assert len(laggy_frames) == 0, f"Frames not synced properly: {laggy_frames=}"
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

@ -86,6 +86,7 @@ class RemoteChunkReader(ChunkReader):
def parse_caibx(caibx_path: str) -> List[Chunk]: def parse_caibx(caibx_path: str) -> List[Chunk]:
"""Parses the chunks from a caibx file. Can handle both local and remote files. """Parses the chunks from a caibx file. Can handle both local and remote files.
Returns a list of chunks with hash, offset and length""" Returns a list of chunks with hash, offset and length"""
caibx: io.BufferedIOBase
if os.path.isfile(caibx_path): if os.path.isfile(caibx_path):
caibx = open(caibx_path, 'rb') caibx = open(caibx_path, 'rb')
else: else:

Loading…
Cancel
Save