Merge remote-tracking branch 'upstream/master' into civic22_long

pull/25364/head
royjr 3 years ago
commit 2c7662f5ec
  1. 6
      .github/workflows/selfdrive_tests.yaml
  2. 2
      .gitignore
  3. 2
      .gitmodules
  4. 4
      .pre-commit-config.yaml
  5. 6
      Dockerfile.openpilot_base
  6. 100
      Pipfile
  7. 3072
      Pipfile.lock
  8. 6
      RELEASES.md
  9. 1
      SConstruct
  10. 2
      cereal
  11. 13
      docs/CARS.md
  12. 7
      docs/docker/Dockerfile
  13. 2
      opendbc
  14. 7968
      poetry.lock
  15. 177
      pyproject.toml
  16. 1
      release/files_common
  17. 68
      selfdrive/athena/tests/test_athenad.py
  18. 8
      selfdrive/car/car_helpers.py
  19. 14
      selfdrive/car/fw_versions.py
  20. 35
      selfdrive/car/gm/carcontroller.py
  21. 23
      selfdrive/car/gm/carstate.py
  22. 49
      selfdrive/car/gm/gmcan.py
  23. 20
      selfdrive/car/gm/interface.py
  24. 4
      selfdrive/car/gm/values.py
  25. 43
      selfdrive/car/honda/values.py
  26. 38
      selfdrive/car/hyundai/carcontroller.py
  27. 23
      selfdrive/car/hyundai/carstate.py
  28. 8
      selfdrive/car/hyundai/hyundaicanfd.py
  29. 115
      selfdrive/car/hyundai/interface.py
  30. 29
      selfdrive/car/hyundai/tests/test_hyundai.py
  31. 114
      selfdrive/car/hyundai/values.py
  32. 8
      selfdrive/car/mazda/values.py
  33. 7
      selfdrive/car/tests/routes.py
  34. 19
      selfdrive/car/tests/test_fw_fingerprint.py
  35. 2
      selfdrive/car/tests/test_models.py
  36. 1
      selfdrive/car/torque_data/override.yaml
  37. 6
      selfdrive/car/torque_data/params.yaml
  38. 1
      selfdrive/car/torque_data/substitute.yaml
  39. 38
      selfdrive/car/toyota/interface.py
  40. 102
      selfdrive/car/toyota/tunes.py
  41. 3
      selfdrive/car/volkswagen/values.py
  42. 66
      selfdrive/controls/controlsd.py
  43. 3
      selfdrive/controls/lib/drive_helpers.py
  44. 2
      selfdrive/controls/lib/events.py
  45. 2
      selfdrive/controls/lib/latcontrol_torque.py
  46. 4
      selfdrive/controls/lib/lateral_planner.py
  47. 3
      selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py
  48. 2
      selfdrive/controls/lib/longitudinal_planner.py
  49. 3
      selfdrive/controls/tests/test_startup.py
  50. 8
      selfdrive/debug/can_print_changes.py
  51. 2
      selfdrive/debug/check_timings.py
  52. 34
      selfdrive/locationd/calibrationd.py
  53. 2
      selfdrive/loggerd/loggerd.cc
  54. 1
      selfdrive/modeld/SConscript
  55. 4
      selfdrive/modeld/models/dmonitoring_model.current
  56. 4
      selfdrive/modeld/models/dmonitoring_model.onnx
  57. 4
      selfdrive/modeld/models/dmonitoring_model_q.dlc
  58. 9
      selfdrive/modeld/models/driving.cc
  59. 43
      selfdrive/modeld/models/driving.h
  60. 4
      selfdrive/modeld/models/supercombo.onnx
  61. 24
      selfdrive/monitoring/driver_monitor.py
  62. 29
      selfdrive/sensord/rawgps/rawgpsd.py
  63. 8
      selfdrive/test/process_replay/model_replay.py
  64. 2
      selfdrive/test/process_replay/model_replay_ref_commit
  65. 2
      selfdrive/test/process_replay/ref_commit
  66. 4
      selfdrive/test/process_replay/test_processes.py
  67. 1
      selfdrive/test/setup_device_ci.sh
  68. 23
      selfdrive/test/test_onroad.py
  69. 6
      selfdrive/test/update_ci_routes.py
  70. 16
      selfdrive/ui/qt/home.cc
  71. 6
      selfdrive/ui/qt/home.h
  72. 4
      selfdrive/ui/qt/offroad/driverview.cc
  73. 2
      selfdrive/ui/qt/offroad/driverview.h
  74. 4
      selfdrive/ui/qt/offroad/software_settings.cc
  75. 2
      selfdrive/ui/qt/offroad/wifiManager.cc
  76. 55
      selfdrive/ui/qt/onroad.cc
  77. 7
      selfdrive/ui/qt/onroad.h
  78. 4
      selfdrive/ui/qt/util.cc
  79. 1
      selfdrive/ui/qt/util.h
  80. 26
      selfdrive/ui/qt/widgets/cameraview.cc
  81. 6
      selfdrive/ui/qt/widgets/cameraview.h
  82. 4
      selfdrive/ui/qt/widgets/controls.cc
  83. 2
      selfdrive/ui/qt/widgets/controls.h
  84. 2
      selfdrive/ui/qt/widgets/scrollview.cc
  85. 391
      selfdrive/ui/translations/main_ar.ts
  86. 46
      selfdrive/ui/translations/main_ja.ts
  87. 50
      selfdrive/ui/translations/main_ko.ts
  88. 391
      selfdrive/ui/translations/main_nl.ts
  89. 391
      selfdrive/ui/translations/main_pl.ts
  90. 46
      selfdrive/ui/translations/main_pt-BR.ts
  91. 397
      selfdrive/ui/translations/main_th.ts
  92. 46
      selfdrive/ui/translations/main_zh-CHS.ts
  93. 46
      selfdrive/ui/translations/main_zh-CHT.ts
  94. 3
      selfdrive/ui/ui.cc
  95. 8
      selfdrive/ui/watch3.cc
  96. 15
      selfdrive/updated.py
  97. 2
      system/hardware/tici/test_power_draw.py
  98. 2
      tinygrad_repo
  99. 9
      tools/README.md
  100. 2
      tools/cabana/.gitignore
  101. Some files were not shown because too many files have changed in this diff Show More

@ -105,7 +105,7 @@ jobs:
# /usr/local/Cellar # /usr/local/Cellar
# ~/github_brew_cache_entries.txt # ~/github_brew_cache_entries.txt
# /tmp/scons_cache # /tmp/scons_cache
# key: macos-${{ hashFiles('tools/mac_setup.sh', 'update_requirements.sh', 'Pipfile*') }} # key: macos-${{ hashFiles('tools/mac_setup.sh', 'update_requirements.sh', 'poetry.lock') }}
# restore-keys: macos- # restore-keys: macos-
# - name: Brew link restored dependencies # - name: Brew link restored dependencies
# run: | # run: |
@ -121,11 +121,11 @@ jobs:
# - name: Build openpilot # - name: Build openpilot
# run: | # run: |
# source tools/openpilot_env.sh # source tools/openpilot_env.sh
# pipenv run selfdrive/manager/build.py # poetry run selfdrive/manager/build.py
# #
# # cleanup scons cache # # cleanup scons cache
# rm -rf /tmp/scons_cache/ # rm -rf /tmp/scons_cache/
# pipenv run scons -j$(nproc) --cache-populate # poetry run scons -j$(nproc) --cache-populate
# - name: Remove pre-existing Homebrew packages for caching # - name: Remove pre-existing Homebrew packages for caching
# if: steps.dependency-cache.outputs.cache-hit != 'true' # if: steps.dependency-cache.outputs.cache-hit != 'true'
# run: | # run: |

2
.gitignore vendored

@ -83,3 +83,5 @@ selfdrive/modeld/models/*.thneed
build/ build/
!**/.gitkeep !**/.gitkeep
poetry.toml

2
.gitmodules vendored

@ -18,4 +18,4 @@
url = ../../commaai/body.git url = ../../commaai/body.git
[submodule "tinygrad"] [submodule "tinygrad"]
path = tinygrad_repo path = tinygrad_repo
url = ../../commaai/tinygrad.git url = https://github.com/geohot/tinygrad.git

@ -78,3 +78,7 @@ repos:
entry: selfdrive/ui/tests/test_translations.py entry: selfdrive/ui/tests/test_translations.py
language: script language: script
pass_filenames: false pass_filenames: false
- repo: https://github.com/python-poetry/poetry
rev: '1.2.2'
hooks:
- id: poetry-check

@ -12,19 +12,19 @@ ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8 ENV LC_ALL en_US.UTF-8
ENV PIPENV_SYSTEM=1 ENV POETRY_VIRTUALENVS_CREATE=false
ENV PYENV_VERSION=3.8.10 ENV PYENV_VERSION=3.8.10
ENV PYENV_ROOT="/root/.pyenv" ENV PYENV_ROOT="/root/.pyenv"
ENV PATH="$PYENV_ROOT/bin:$PYENV_ROOT/shims:$PATH" ENV PATH="$PYENV_ROOT/bin:$PYENV_ROOT/shims:$PATH"
COPY Pipfile Pipfile.lock .python-version update_requirements.sh /tmp/ COPY pyproject.toml poetry.lock .python-version update_requirements.sh /tmp/
COPY tools/ubuntu_setup.sh /tmp/tools/ COPY tools/ubuntu_setup.sh /tmp/tools/
RUN cd /tmp && \ RUN cd /tmp && \
tools/ubuntu_setup.sh && \ tools/ubuntu_setup.sh && \
rm -rf /var/lib/apt/lists/* && \ rm -rf /var/lib/apt/lists/* && \
rm -rf /tmp/* && \ rm -rf /tmp/* && \
rm -rf /root/.cache && \ rm -rf /root/.cache && \
pip uninstall -y pipenv && \ pip uninstall -y poetry && \
# remove unused architectures from gcc for panda # remove unused architectures from gcc for panda
cd /usr/lib/gcc/arm-none-eabi/9.2.1 && \ cd /usr/lib/gcc/arm-none-eabi/9.2.1 && \
rm -rf arm/ && \ rm -rf arm/ && \

@ -1,100 +0,0 @@
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true
[dev-packages]
av = "*"
azure-storage-blob = "~=2.1"
control = "*"
coverage = "*"
dictdiffer = "*"
fastcluster = "*"
hexdump = "*"
hypothesis = "==6.46.7"
inputs = "*"
lru-dict = "*"
markdown-it-py = "*"
matplotlib = "*"
mypy = "*"
myst-parser = "*"
natsort = "*"
numpy = "*"
opencv-python-headless = "*"
parameterized = "*"
paramiko = "*"
pprofile = "*"
pre-commit = "*"
pycurl = "*"
pygame = "*"
pyprof2calltree = "*"
pytest = "*"
pytest-xdist = "*"
reverse_geocoder = "*"
scipy = "*"
sphinx = "*"
sphinx-sitemap = "*"
sphinx-rtd-theme = "*"
breathe = "*"
subprocess32 = "*"
tenacity = "*"
mpld3 = "*"
carla = {version = "==0.9.13", markers="platform_system != 'Darwin'"}
ft4222 = "*"
pandas = "*"
tabulate = "*"
types-pyyaml = "*"
lxml = "*"
types-atomicwrites = "*"
types-pycurl = "*"
types-requests = "*"
types-certifi = "*"
[packages]
atomicwrites = "*"
casadi = {version = "*", markers="platform_system != 'Darwin'"}
cffi = "*"
crcmod = "*"
cryptography = "*"
Cython = "*"
flake8 = "*"
Flask = "*"
future-fstrings = "*" # for acados
gunicorn = "*"
hexdump = "*"
Jinja2 = "*"
json-rpc = "*"
libusb1 = "*"
nose = "*"
numpy = "*"
protobuf = "==3.20.1"
onnx = "*"
onnxruntime-gpu = {version = "*", markers="platform_system != 'Darwin'"}
pillow = "*"
psutil = "*"
pycapnp = "==1.1.0"
pycryptodome = "*"
PyJWT = "*"
pylint = "*"
pyopencl = "*"
pyserial = "*"
python-dateutil = "*"
PyYAML = "*"
pyzmq = "*"
requests = "*"
scons = "*"
sentry-sdk = "*"
setproctitle = "*"
six = "*"
smbus2 = "*"
sympy = "!=1.6.1"
timezonefinder = "*"
tqdm = "*"
urllib3 = "*"
utm = "*"
websocket_client = "*"
hatanaka = "==2.4"
PySide2 = "*"
[requires]
python_version = "3.8"

3072
Pipfile.lock generated

File diff suppressed because it is too large Load Diff

@ -2,9 +2,11 @@ Version 0.8.17 (2022-XX-XX)
======================== ========================
* New driving model * New driving model
* Internal feature space accuracy increased tenfold during training, this makes the model dramatically more accurate. * Internal feature space accuracy increased tenfold during training, this makes the model dramatically more accurate.
* New driver monitoring model
* New end-to-end distracted trigger
* Self-tuning torque lateral controller parameters * Self-tuning torque lateral controller parameters
* Parameters learned live for each car * Parameters learned live for each car
* Enabled only on Toyota Corolla for now * Torque controller used on all Toyota, Lexus, Hyundai, Kia, and Genesis models
* UI updates * UI updates
* Multi-language in navigation * Multi-language in navigation
* Matched speeds shown on car's dash * Matched speeds shown on car's dash
@ -12,6 +14,8 @@ Version 0.8.17 (2022-XX-XX)
* Border turns grey while overriding steering * Border turns grey while overriding steering
* Added button to bookmark events while driving; view them later in comma connect * Added button to bookmark events while driving; view them later in comma connect
* AGNOS 6 * AGNOS 6
* tools: new and improved cabana thanks to deanlee!
* Kia Sportage Hybrid 2023 support thanks to sunnyhaibin!
Version 0.8.16 (2022-08-26) Version 0.8.16 (2022-08-26)
======================== ========================

@ -327,6 +327,7 @@ qt_flags = [
qt_env['CXXFLAGS'] += qt_flags qt_env['CXXFLAGS'] += qt_flags
qt_env['LIBPATH'] += ['#selfdrive/ui'] qt_env['LIBPATH'] += ['#selfdrive/ui']
qt_env['LIBS'] = qt_libs qt_env['LIBS'] = qt_libs
qt_env['QT_MOCHPREFIX'] = cache_dir + '/moc_files/moc_'
if GetOption("clazy"): if GetOption("clazy"):
checks = [ checks = [

@ -1 +1 @@
Subproject commit 5766e645f2ee2a131b145fb1ea9e3b7c55a4a740 Subproject commit 1d25fc3f202d5ddeee97848480323e9b14f9bdfa

@ -4,7 +4,7 @@
A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system.
# 208 Supported Cars # 211 Supported Cars
|Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness| |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness|
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|
@ -18,8 +18,8 @@ A supported vehicle is one that just works when you install a comma three. All s
|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| |Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| |Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Cadillac|Escalade ESV 2016[<sup>1</sup>](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| |Cadillac|Escalade ESV 2016[<sup>1</sup>](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|
|Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|Stock|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| |Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|Stock|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|
|Chevrolet|Silverado 1500 2020-21|Safety Package II|Stock|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| |Chevrolet|Silverado 1500 2020-21|Safety Package II|Stock|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|
|Chevrolet|Volt 2017-18[<sup>1</sup>](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| |Chevrolet|Volt 2017-18[<sup>1</sup>](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|
|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| |Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|
|Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| |Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|
@ -32,7 +32,7 @@ A supported vehicle is one that just works when you install a comma three. All s
|Genesis|G80 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| |Genesis|G80 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|
|Genesis|G90 2017-18|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |Genesis|G90 2017-18|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|
|GMC|Acadia 2018[<sup>1</sup>](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| |GMC|Acadia 2018[<sup>1</sup>](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|
|GMC|Sierra 1500 2020-21|Driver Alert Package II|Stock|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| |GMC|Sierra 1500 2020-21|Driver Alert Package II|Stock|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|
|Honda|Accord 2018-22|All|openpilot|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| |Honda|Accord 2018-22|All|openpilot|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|
|Honda|Accord Hybrid 2018-22|All|openpilot|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| |Honda|Accord Hybrid 2018-22|All|openpilot|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|
|Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| |Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|
@ -55,8 +55,10 @@ A supported vehicle is one that just works when you install a comma three. All s
|Honda|Ridgeline 2017-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| |Honda|Ridgeline 2017-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|
|Hyundai|Elantra 2017-19|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B| |Hyundai|Elantra 2017-19|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B|
|Hyundai|Elantra 2021-22|Smart Cruise Control (SCC)|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| |Hyundai|Elantra 2021-22|Smart Cruise Control (SCC)|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|
|Hyundai|Elantra GT 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|
|Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| |Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|
|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai J| |Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai J|
|Hyundai|i30 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|
|Hyundai|Ioniq 5 (with HDA II) 2022|Highway Driving Assist II|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai Q| |Hyundai|Ioniq 5 (with HDA II) 2022|Highway Driving Assist II|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai Q|
|Hyundai|Ioniq 5 (without HDA II) 2022|Highway Driving Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| |Hyundai|Ioniq 5 (without HDA II) 2022|Highway Driving Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|
|Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|
@ -100,6 +102,7 @@ A supported vehicle is one that just works when you install a comma three. All s
|Kia|Seltos 2021|Smart Cruise Control (SCC)|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| |Kia|Seltos 2021|Smart Cruise Control (SCC)|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|
|Kia|Sorento 2018|Advanced Smart Cruise Control|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |Kia|Sorento 2018|Advanced Smart Cruise Control|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|
|Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| |Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|
|Kia|Sportage Hybrid 2023|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|
|Kia|Stinger 2018-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |Kia|Stinger 2018-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|
|Kia|Telluride 2020|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| |Kia|Telluride 2020|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|
|Lexus|CT Hybrid 2017-18|Lexus Safety System+|Stock[<sup>3</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Lexus|CT Hybrid 2017-18|Lexus Safety System+|Stock[<sup>3</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
@ -119,7 +122,7 @@ A supported vehicle is one that just works when you install a comma three. All s
|Lexus|RX Hybrid 2017-19|All|Stock[<sup>3</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Lexus|RX Hybrid 2017-19|All|Stock[<sup>3</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Lexus|RX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Lexus|RX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
|Lexus|UX Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Lexus|UX Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
|Mazda|CX-5 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Mazda| |Mazda|CX-5 2022-23|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Mazda|
|Mazda|CX-9 2021-22|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Mazda| |Mazda|CX-9 2021-22|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Mazda|
|Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan B| |Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan B|
|Nissan|Leaf 2018-22|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A| |Nissan|Leaf 2018-22|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A|

@ -4,16 +4,11 @@ ENV PYTHONUNBUFFERED 1
ENV OPENPILOT_PATH /home/batman/openpilot/ ENV OPENPILOT_PATH /home/batman/openpilot/
ENV PYTHONPATH ${OPENPILOT_PATH}:${PYTHONPATH} ENV PYTHONPATH ${OPENPILOT_PATH}:${PYTHONPATH}
ENV POETRY_VIRUALENVS_CREATE false
RUN mkdir -p ${OPENPILOT_PATH} RUN mkdir -p ${OPENPILOT_PATH}
WORKDIR ${OPENPILOT_PATH} WORKDIR ${OPENPILOT_PATH}
COPY Pipfile Pipfile.lock $OPENPILOT_PATH
RUN pip install --no-cache-dir pipenv==2021.5.29 pip==21.3.1 && \
pipenv install --system --deploy --dev --clear && \
pip uninstall -y pipenv
COPY SConstruct ${OPENPILOT_PATH} COPY SConstruct ${OPENPILOT_PATH}
COPY ./pyextra ${OPENPILOT_PATH}/pyextra COPY ./pyextra ${OPENPILOT_PATH}/pyextra

@ -1 +1 @@
Subproject commit dde0ff6f4456c167df204bf5ac1e3f2979c844c9 Subproject commit a95b0ae8a5244a9d6311bf72aa2a7d63d41b4a9f

7968
poetry.lock generated

File diff suppressed because it is too large Load Diff

@ -0,0 +1,177 @@
[tool.poetry]
name = "openpilot"
version = "0.1.0"
description = "an open source driver assistance system"
authors = ["Vehicle Researcher <user@comma.ai>"]
license = "MIT"
readme = "README.md"
repository = "https://github.com/commaai/openpilot"
documentation = "https://docs.comma.ai"
[tool.poetry.dependencies]
python = "~3.8"
atomicwrites = "^1.4.0"
casadi = { version = "==3.5.5", markers = "platform_system != 'Darwin'" }
cffi = "^1.15.1"
crcmod = "^1.7"
cryptography = "^37.0.4"
Cython = "^0.29.30"
flake8 = "^4.0.1"
Flask = "^2.1.2"
future-fstrings = "^1.2.0" # for acados
gunicorn = "^20.1.0"
hatanaka = "==2.4"
hexdump = "^3.3"
Jinja2 = "^3.1.2"
json-rpc = "^1.13.0"
libusb1 = "^3.0.0"
nose = "^1.3.7"
numpy = "^1.23.0"
onnx = "^1.12.0"
onnxruntime-gpu = { version = "^1.11.1", markers = "platform_system != 'Darwin'" }
pillow = "^9.2.0"
poetry = "==1.2.2"
protobuf = "==3.20.1"
psutil = "^5.9.1"
pycapnp = "==1.1.0"
pycryptodome = "^3.15.0"
PyJWT = "^2.5.0"
pylint = "^2.15.4"
pyopencl = "^2022.2.4"
pyserial = "^3.5"
python-dateutil = "^2.8.2"
PyYAML = "^6.0"
pyzmq = "^23.2.0"
requests = "^2.28.1"
scons = "^4.3.0"
sentry-sdk = "^1.6.0"
setproctitle = "^1.2.3"
six = "^1.16.0"
smbus2 = "^0.4.2"
sympy = "^1.10.1"
timezonefinder = "^6.0.1"
tqdm = "^4.64.0"
urllib3 = "^1.26.10"
utm = "^0.7.0"
websocket_client = "^1.3.3"
[tool.poetry.group.dev.dependencies]
av = "^9.2.0"
azure-storage-blob = "~2.1"
breathe = "^4.34.0"
carla = "==0.9.13"
control = "^0.9.2"
coverage = "^6.4.1"
dictdiffer = "^0.9.0"
fastcluster = "^1.2.6"
ft4222 = "^1.4.1"
hexdump = "^3.3"
hypothesis = "==6.46.7"
inputs = "^0.5"
lru-dict = "^1.1.7"
lxml = "^4.9.1"
markdown-it-py = "^2.1.0"
matplotlib = "^3.5.2"
mpld3 = "^0.5.8"
mypy = "^0.961"
myst-parser = "^0.18.0"
natsort = "^8.1.0"
numpy = "^1.23.0"
opencv-python-headless = { url = "https://github.com/commaai/opencv-python-builder/releases/download/4.5.5.64%2Bcu113/opencv_python_headless-4.5.5.64-cp38-cp38-manylinux_2_31_x86_64.whl" }
pandas = "^1.4.3"
parameterized = "^0.8.1"
paramiko = "^2.11.0"
pprofile = "^2.1.0"
pre-commit = "^2.19.0"
pycurl = "^7.45.1"
pygame = "^2.1.2"
pyprof2calltree = "^1.4.5"
pytest = "^7.1.2"
pytest-xdist = "^2.5.0"
reverse_geocoder = "^1.5.1"
scipy = "^1.8.1"
sphinx = "^5.0.2"
sphinx-rtd-theme = "^1.0.0"
sphinx-sitemap = "^2.2.0"
subprocess32 = "^3.5.4"
tabulate = "^0.8.10"
tenacity = "^8.0.1"
types-atomicwrites = "^1.4.5"
types-certifi = "^2021.10.8"
types-pycurl = "^7.45.1"
types-PyYAML = "^6.0"
types-requests = "^2.28.11"
[tool.poetry.group.xx]
optional = true
[tool.poetry.group.xx.dependencies]
aenum = "^3.1.11"
aiohttp = "^3.8.1"
albumentations = "^1.2.1"
apex = { url = "https://github.com/commaai/apex/releases/download/pytorch1.10.0%2Bcu11.1/apex-0.1-cp38-cp38-linux_x86_64.whl" }
azure-cli-core = "^2.38.0"
azure-common = "^1.1.28"
azure-core = "^1.24.2"
azure-nspkg = "~3.0"
azure-storage-blob = "~2.1"
azure-storage-common = "~2.1"
azure-storage-nspkg = "~3.1"
blosc = "==1.9.2"
cloudpickle = "^2.1.0"
configargparse = "^1.5.3"
cupy-cuda113 = "^10.6.0"
datadog = "^0.44.0"
dotmap = "^1.3.30"
einops = "^0.5.0"
elasticsearch = "^8.3.1"
Flask-Cors = "^3.0.10"
Flask-SocketIO = "^5.2.0"
GeoAlchemy2 = "^0.12.1"
imageio = "^2.19.5"
influxdb-client = "^1.30.0"
ipykernel = "^6.15.1"
ipython = "^8.4.0"
joblib = "^1.1.0"
json-logging-py = "^0.2"
jupyter = "^1.0.0"
jupyterlab = "^3.4.4"
jupyterlab-vim = "^0.15.1"
Markdown = "^3.4.1"
mpld3 = "^0.5.8"
msgpack-python = "^0.5.6"
networkx = "~2.3"
nvidia-ml-py3 = "^7.352.0"
onnxoptimizer = "^0.3.1"
opencv-python-headless = { url = "https://github.com/commaai/opencv-python-builder/releases/download/4.5.5.64%2Bcu113/opencv_python_headless-4.5.5.64-cp38-cp38-manylinux_2_31_x86_64.whl" }
osmium = "^3.3.0"
pandas = "^1.4.3"
pillow-avif-plugin = "^1.2.2"
pipenv = "==2022.10.12"
plotly = "^5.9.0"
pycuda = "^2022.1"
Pygments = "^2.12.0"
PyMySQL = "~0.9"
pyproj = "^3.3.1"
python-logstash = "^0.4.8"
redis = "^4.3.4"
s2sphere = "^0.2.5"
scikit-image = "^0.19.3"
scikit-learn = "^1.1.1"
segmentation-models-pytorch = "==0.2.1"
simplejson = "^3.17.6"
SQLAlchemy = "^1.4.39"
torch = { url = "https://download.pytorch.org/whl/cu113/torch-1.11.0%2Bcu113-cp38-cp38-linux_x86_64.whl" }
torchsummary = "^1.5.1"
torchvision = { url = "https://download.pytorch.org/whl/cu113/torchvision-0.12.0%2Bcu113-cp38-cp38-linux_x86_64.whl" }
triton = "^1.1.1"
Werkzeug = "^2.1.2"
zerorpc = { git = "https://github.com/commaai/zerorpc-python.git", branch = "master" }
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

@ -565,6 +565,7 @@ opendbc/tesla_powertrain.dbc
tinygrad_repo/openpilot/compile.py tinygrad_repo/openpilot/compile.py
tinygrad_repo/accel/opencl/* tinygrad_repo/accel/opencl/*
tinygrad_repo/extra/onnx.py tinygrad_repo/extra/onnx.py
tinygrad_repo/extra/thneed.py
tinygrad_repo/extra/utils.py tinygrad_repo/extra/utils.py
tinygrad_repo/tinygrad/llops/ops_gpu.py tinygrad_repo/tinygrad/llops/ops_gpu.py
tinygrad_repo/tinygrad/llops/ops_opencl.py tinygrad_repo/tinygrad/llops/ops_opencl.py

@ -9,6 +9,7 @@ import threading
import queue import queue
import unittest import unittest
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import Optional
from multiprocessing import Process from multiprocessing import Process
from pathlib import Path from pathlib import Path
@ -46,12 +47,26 @@ class TestAthenadMethods(unittest.TestCase):
else: else:
os.unlink(p) os.unlink(p)
def wait_for_upload(self):
# *** test helpers ***
@staticmethod
def _wait_for_upload():
now = time.time() now = time.time()
while time.time() - now < 5: while time.time() - now < 5:
if athenad.upload_queue.qsize() == 0: if athenad.upload_queue.qsize() == 0:
break break
@staticmethod
def _create_file(file: str, parent: Optional[str] = None) -> str:
fn = os.path.join(athenad.ROOT if parent is None else parent, file)
os.makedirs(os.path.dirname(fn), exist_ok=True)
Path(fn).touch()
return fn
# *** test cases ***
def test_echo(self): def test_echo(self):
assert dispatcher["echo"]("bob") == "bob" assert dispatcher["echo"]("bob") == "bob"
@ -85,9 +100,7 @@ class TestAthenadMethods(unittest.TestCase):
filenames = ['qlog', 'qcamera.ts', 'rlog', 'fcamera.hevc', 'ecamera.hevc', 'dcamera.hevc'] filenames = ['qlog', 'qcamera.ts', 'rlog', 'fcamera.hevc', 'ecamera.hevc', 'dcamera.hevc']
files = [f'{route}--{s}/{f}' for s in segments for f in filenames] files = [f'{route}--{s}/{f}' for s in segments for f in filenames]
for file in files: for file in files:
fn = os.path.join(athenad.ROOT, file) self._create_file(file)
os.makedirs(os.path.dirname(fn), exist_ok=True)
Path(fn).touch()
resp = dispatcher["listDataDirectory"]() resp = dispatcher["listDataDirectory"]()
self.assertTrue(resp, 'list empty!') self.assertTrue(resp, 'list empty!')
@ -121,16 +134,14 @@ class TestAthenadMethods(unittest.TestCase):
self.assertCountEqual(resp, expected) self.assertCountEqual(resp, expected)
def test_strip_bz2_extension(self): def test_strip_bz2_extension(self):
fn = os.path.join(athenad.ROOT, 'qlog.bz2') fn = self._create_file('qlog.bz2')
Path(fn).touch()
if fn.endswith('.bz2'): if fn.endswith('.bz2'):
self.assertEqual(athenad.strip_bz2_extension(fn), fn[:-4]) self.assertEqual(athenad.strip_bz2_extension(fn), fn[:-4])
@with_http_server @with_http_server
def test_do_upload(self, host): def test_do_upload(self, host):
fn = os.path.join(athenad.ROOT, 'qlog.bz2') fn = self._create_file('qlog.bz2')
Path(fn).touch()
item = athenad.UploadItem(path=fn, url="http://localhost:1238", headers={}, created_at=int(time.time()*1000), id='') item = athenad.UploadItem(path=fn, url="http://localhost:1238", headers={}, created_at=int(time.time()*1000), id='')
with self.assertRaises(requests.exceptions.ConnectionError): with self.assertRaises(requests.exceptions.ConnectionError):
@ -142,8 +153,7 @@ class TestAthenadMethods(unittest.TestCase):
@with_http_server @with_http_server
def test_uploadFileToUrl(self, host): def test_uploadFileToUrl(self, host):
fn = os.path.join(athenad.ROOT, 'qlog.bz2') fn = self._create_file('qlog.bz2')
Path(fn).touch()
resp = dispatcher["uploadFileToUrl"]("qlog.bz2", f"{host}/qlog.bz2", {}) resp = dispatcher["uploadFileToUrl"]("qlog.bz2", f"{host}/qlog.bz2", {})
self.assertEqual(resp['enqueued'], 1) self.assertEqual(resp['enqueued'], 1)
@ -154,8 +164,7 @@ class TestAthenadMethods(unittest.TestCase):
@with_http_server @with_http_server
def test_uploadFileToUrl_duplicate(self, host): def test_uploadFileToUrl_duplicate(self, host):
fn = os.path.join(athenad.ROOT, 'qlog.bz2') self._create_file('qlog.bz2')
Path(fn).touch()
url1 = f"{host}/qlog.bz2?sig=sig1" url1 = f"{host}/qlog.bz2?sig=sig1"
dispatcher["uploadFileToUrl"]("qlog.bz2", url1, {}) dispatcher["uploadFileToUrl"]("qlog.bz2", url1, {})
@ -172,8 +181,7 @@ class TestAthenadMethods(unittest.TestCase):
@with_http_server @with_http_server
def test_upload_handler(self, host): def test_upload_handler(self, host):
fn = os.path.join(athenad.ROOT, 'qlog.bz2') fn = self._create_file('qlog.bz2')
Path(fn).touch()
item = athenad.UploadItem(path=fn, url=f"{host}/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True) item = athenad.UploadItem(path=fn, url=f"{host}/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True)
end_event = threading.Event() end_event = threading.Event()
@ -182,7 +190,7 @@ class TestAthenadMethods(unittest.TestCase):
athenad.upload_queue.put_nowait(item) athenad.upload_queue.put_nowait(item)
try: try:
self.wait_for_upload() self._wait_for_upload()
time.sleep(0.1) time.sleep(0.1)
# TODO: verify that upload actually succeeded # TODO: verify that upload actually succeeded
@ -195,8 +203,7 @@ class TestAthenadMethods(unittest.TestCase):
def test_upload_handler_retry(self, host, mock_put): def test_upload_handler_retry(self, host, mock_put):
for status, retry in ((500, True), (412, False)): for status, retry in ((500, True), (412, False)):
mock_put.return_value.status_code = status mock_put.return_value.status_code = status
fn = os.path.join(athenad.ROOT, 'qlog.bz2') fn = self._create_file('qlog.bz2')
Path(fn).touch()
item = athenad.UploadItem(path=fn, url=f"{host}/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True) item = athenad.UploadItem(path=fn, url=f"{host}/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True)
end_event = threading.Event() end_event = threading.Event()
@ -205,7 +212,7 @@ class TestAthenadMethods(unittest.TestCase):
athenad.upload_queue.put_nowait(item) athenad.upload_queue.put_nowait(item)
try: try:
self.wait_for_upload() self._wait_for_upload()
time.sleep(0.1) time.sleep(0.1)
self.assertEqual(athenad.upload_queue.qsize(), 1 if retry else 0) self.assertEqual(athenad.upload_queue.qsize(), 1 if retry else 0)
@ -217,8 +224,7 @@ class TestAthenadMethods(unittest.TestCase):
def test_upload_handler_timeout(self): def test_upload_handler_timeout(self):
"""When an upload times out or fails to connect it should be placed back in the queue""" """When an upload times out or fails to connect it should be placed back in the queue"""
fn = os.path.join(athenad.ROOT, 'qlog.bz2') fn = self._create_file('qlog.bz2')
Path(fn).touch()
item = athenad.UploadItem(path=fn, url="http://localhost:44444/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True) item = athenad.UploadItem(path=fn, url="http://localhost:44444/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True)
item_no_retry = item._replace(retry_count=MAX_RETRY_COUNT) item_no_retry = item._replace(retry_count=MAX_RETRY_COUNT)
@ -228,14 +234,14 @@ class TestAthenadMethods(unittest.TestCase):
try: try:
athenad.upload_queue.put_nowait(item_no_retry) athenad.upload_queue.put_nowait(item_no_retry)
self.wait_for_upload() self._wait_for_upload()
time.sleep(0.1) time.sleep(0.1)
# Check that upload with retry count exceeded is not put back # Check that upload with retry count exceeded is not put back
self.assertEqual(athenad.upload_queue.qsize(), 0) self.assertEqual(athenad.upload_queue.qsize(), 0)
athenad.upload_queue.put_nowait(item) athenad.upload_queue.put_nowait(item)
self.wait_for_upload() self._wait_for_upload()
time.sleep(0.1) time.sleep(0.1)
# Check that upload item was put back in the queue with incremented retry count # Check that upload item was put back in the queue with incremented retry count
@ -256,7 +262,7 @@ class TestAthenadMethods(unittest.TestCase):
thread = threading.Thread(target=athenad.upload_handler, args=(end_event,)) thread = threading.Thread(target=athenad.upload_handler, args=(end_event,))
thread.start() thread.start()
try: try:
self.wait_for_upload() self._wait_for_upload()
time.sleep(0.1) time.sleep(0.1)
self.assertEqual(athenad.upload_queue.qsize(), 0) self.assertEqual(athenad.upload_queue.qsize(), 0)
@ -269,8 +275,7 @@ class TestAthenadMethods(unittest.TestCase):
ts = int(t_future.strftime("%s")) * 1000 ts = int(t_future.strftime("%s")) * 1000
# Item that would time out if actually uploaded # Item that would time out if actually uploaded
fn = os.path.join(athenad.ROOT, 'qlog.bz2') fn = self._create_file('qlog.bz2')
Path(fn).touch()
item = athenad.UploadItem(path=fn, url="http://localhost:44444/qlog.bz2", headers={}, created_at=ts, id='', allow_cellular=True) item = athenad.UploadItem(path=fn, url="http://localhost:44444/qlog.bz2", headers={}, created_at=ts, id='', allow_cellular=True)
@ -279,7 +284,7 @@ class TestAthenadMethods(unittest.TestCase):
thread.start() thread.start()
try: try:
athenad.upload_queue.put_nowait(item) athenad.upload_queue.put_nowait(item)
self.wait_for_upload() self._wait_for_upload()
time.sleep(0.1) time.sleep(0.1)
self.assertEqual(athenad.upload_queue.qsize(), 0) self.assertEqual(athenad.upload_queue.qsize(), 0)
@ -292,8 +297,7 @@ class TestAthenadMethods(unittest.TestCase):
@with_http_server @with_http_server
def test_listUploadQueueCurrent(self, host): def test_listUploadQueueCurrent(self, host):
fn = os.path.join(athenad.ROOT, 'qlog.bz2') fn = self._create_file('qlog.bz2')
Path(fn).touch()
item = athenad.UploadItem(path=fn, url=f"{host}/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True) item = athenad.UploadItem(path=fn, url=f"{host}/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True)
end_event = threading.Event() end_event = threading.Event()
@ -302,7 +306,7 @@ class TestAthenadMethods(unittest.TestCase):
try: try:
athenad.upload_queue.put_nowait(item) athenad.upload_queue.put_nowait(item)
self.wait_for_upload() self._wait_for_upload()
items = dispatcher["listUploadQueue"]() items = dispatcher["listUploadQueue"]()
self.assertEqual(len(items), 1) self.assertEqual(len(items), 1)
@ -405,9 +409,9 @@ class TestAthenadMethods(unittest.TestCase):
def test_get_logs_to_send_sorted(self): def test_get_logs_to_send_sorted(self):
fl = list() fl = list()
for i in range(10): for i in range(10):
fn = os.path.join(swaglog.SWAGLOG_DIR, f'swaglog.{i:010}') file = f'swaglog.{i:010}'
Path(fn).touch() self._create_file(file, athenad.SWAGLOG_DIR)
fl.append(os.path.basename(fn)) fl.append(file)
# ensure the list is all logs except most recent # ensure the list is all logs except most recent
sl = athenad.get_logs_to_send_sorted() sl = athenad.get_logs_to_send_sorted()

@ -76,7 +76,7 @@ interfaces = load_interfaces(interface_names)
# **** for use live only **** # **** for use live only ****
def fingerprint(logcan, sendcan): def fingerprint(logcan, sendcan, num_pandas):
fixed_fingerprint = os.environ.get('FINGERPRINT', "") fixed_fingerprint = os.environ.get('FINGERPRINT', "")
skip_fw_query = os.environ.get('SKIP_FW_QUERY', False) skip_fw_query = os.environ.get('SKIP_FW_QUERY', False)
ecu_rx_addrs = set() ecu_rx_addrs = set()
@ -100,7 +100,7 @@ def fingerprint(logcan, sendcan):
cloudlog.warning("Getting VIN & FW versions") cloudlog.warning("Getting VIN & FW versions")
vin_rx_addr, vin = get_vin(logcan, sendcan, bus) vin_rx_addr, vin = get_vin(logcan, sendcan, bus)
ecu_rx_addrs = get_present_ecus(logcan, sendcan) ecu_rx_addrs = get_present_ecus(logcan, sendcan)
car_fw = get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs) car_fw = get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, num_pandas=num_pandas)
cached = False cached = False
exact_fw_match, fw_candidates = match_fw_to_car(car_fw) exact_fw_match, fw_candidates = match_fw_to_car(car_fw)
@ -173,8 +173,8 @@ def fingerprint(logcan, sendcan):
return car_fingerprint, finger, vin, car_fw, source, exact_match return car_fingerprint, finger, vin, car_fw, source, exact_match
def get_car(logcan, sendcan): def get_car(logcan, sendcan, num_pandas=1):
candidate, fingerprints, vin, car_fw, source, exact_match = fingerprint(logcan, sendcan) candidate, fingerprints, vin, car_fw, source, exact_match = fingerprint(logcan, sendcan, num_pandas)
if candidate is None: if candidate is None:
cloudlog.warning("car doesn't match any fingerprints: %r", fingerprints) cloudlog.warning("car doesn't match any fingerprints: %r", fingerprints)

@ -194,14 +194,14 @@ def get_brand_ecu_matches(ecu_rx_addrs):
return brand_matches return brand_matches
def get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, timeout=0.1, debug=False, progress=False): def get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, timeout=0.1, num_pandas=1, debug=False, progress=False):
"""Queries for FW versions ordering brands by likelihood, breaks when exact match is found""" """Queries for FW versions ordering brands by likelihood, breaks when exact match is found"""
all_car_fw = [] all_car_fw = []
brand_matches = get_brand_ecu_matches(ecu_rx_addrs) brand_matches = get_brand_ecu_matches(ecu_rx_addrs)
for brand in sorted(brand_matches, key=lambda b: len(brand_matches[b]), reverse=True): for brand in sorted(brand_matches, key=lambda b: len(brand_matches[b]), reverse=True):
car_fw = get_fw_versions(logcan, sendcan, query_brand=brand, timeout=timeout, debug=debug, progress=progress) car_fw = get_fw_versions(logcan, sendcan, query_brand=brand, timeout=timeout, num_pandas=num_pandas, debug=debug, progress=progress)
all_car_fw.extend(car_fw) all_car_fw.extend(car_fw)
# Try to match using FW returned from this brand only # Try to match using FW returned from this brand only
matches = match_fw_to_car_exact(build_fw_dict(car_fw)) matches = match_fw_to_car_exact(build_fw_dict(car_fw))
@ -211,7 +211,7 @@ def get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, timeout=0.1, debug=Fa
return all_car_fw return all_car_fw
def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, debug=False, progress=False): def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, num_pandas=1, debug=False, progress=False):
versions = VERSIONS.copy() versions = VERSIONS.copy()
# Each brand can define extra ECUs to query for data collection # Each brand can define extra ECUs to query for data collection
@ -252,6 +252,10 @@ def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1,
for addr in tqdm(addrs, disable=not progress): for addr in tqdm(addrs, disable=not progress):
for addr_chunk in chunks(addr): for addr_chunk in chunks(addr):
for brand, r in requests: for brand, r in requests:
# Skip query if no panda available
if r.bus > num_pandas * 4 - 1:
continue
try: try:
addrs = [(a, s) for (b, a, s) in addr_chunk if b in (brand, 'any') and addrs = [(a, s) for (b, a, s) in addr_chunk if b in (brand, 'any') and
(len(r.whitelist_ecus) == 0 or ecu_types[(b, a, s)] in r.whitelist_ecus)] (len(r.whitelist_ecus) == 0 or ecu_types[(b, a, s)] in r.whitelist_ecus)]
@ -292,6 +296,7 @@ if __name__ == "__main__":
args = parser.parse_args() args = parser.parse_args()
logcan = messaging.sub_sock('can') logcan = messaging.sub_sock('can')
pandaStates_sock = messaging.sub_sock('pandaStates')
sendcan = messaging.pub_sock('sendcan') sendcan = messaging.pub_sock('sendcan')
extra: Any = None extra: Any = None
@ -305,6 +310,7 @@ if __name__ == "__main__":
extra = {"any": {"debug": extra}} extra = {"any": {"debug": extra}}
time.sleep(1.) time.sleep(1.)
num_pandas = len(messaging.recv_one_retry(pandaStates_sock).pandaStates)
t = time.time() t = time.time()
print("Getting vin...") print("Getting vin...")
@ -314,7 +320,7 @@ if __name__ == "__main__":
print() print()
t = time.time() t = time.time()
fw_vers = get_fw_versions(logcan, sendcan, query_brand=args.brand, extra=extra, debug=args.debug, progress=True) fw_vers = get_fw_versions(logcan, sendcan, query_brand=args.brand, extra=extra, num_pandas=num_pandas, debug=args.debug, progress=True)
_, candidates = match_fw_to_car(fw_vers) _, candidates = match_fw_to_car(fw_vers)
print() print()

@ -10,6 +10,9 @@ from selfdrive.car.gm.values import DBC, CanBus, CarControllerParams, CruiseButt
VisualAlert = car.CarControl.HUDControl.VisualAlert VisualAlert = car.CarControl.HUDControl.VisualAlert
NetworkLocation = car.CarParams.NetworkLocation NetworkLocation = car.CarParams.NetworkLocation
# Camera cancels up to 0.1s after brake is pressed, ECM allows 0.5s
CAMERA_CANCEL_DELAY_FRAMES = 10
class CarController: class CarController:
def __init__(self, dbc_name, CP, VM): def __init__(self, dbc_name, CP, VM):
@ -19,7 +22,9 @@ class CarController:
self.apply_gas = 0 self.apply_gas = 0
self.apply_brake = 0 self.apply_brake = 0
self.frame = 0 self.frame = 0
self.last_steer_frame = 0
self.last_button_frame = 0 self.last_button_frame = 0
self.cancel_counter = 0
self.lka_steering_cmd_counter = 0 self.lka_steering_cmd_counter = 0
self.sent_lka_steering_cmd = False self.sent_lka_steering_cmd = False
@ -42,15 +47,21 @@ class CarController:
# Send CAN commands. # Send CAN commands.
can_sends = [] can_sends = []
# Steering (50Hz) # Steering (Active: 50Hz, inactive: 10Hz)
# Attempt to sync with camera on startup at 50Hz, first few msgs are blocked
init_lka_counter = not self.sent_lka_steering_cmd and self.CP.networkLocation == NetworkLocation.fwdCamera
steer_step = self.params.INACTIVE_STEER_STEP
if CC.latActive or init_lka_counter:
steer_step = self.params.ACTIVE_STEER_STEP
# Avoid GM EPS faults when transmitting messages too close together: skip this transmit if we just received the # Avoid GM EPS faults when transmitting messages too close together: skip this transmit if we just received the
# next Panda loopback confirmation in the current CS frame. # next Panda loopback confirmation in the current CS frame.
if CS.loopback_lka_steering_cmd_updated: if CS.loopback_lka_steering_cmd_updated:
self.lka_steering_cmd_counter += 1 self.lka_steering_cmd_counter += 1
self.sent_lka_steering_cmd = True self.sent_lka_steering_cmd = True
elif (self.frame % self.params.STEER_STEP) == 0: elif (self.frame - self.last_steer_frame) >= steer_step:
# Initialize ASCMLKASteeringCmd counter using the camera # Initialize ASCMLKASteeringCmd counter using the camera until we get a msg on the bus
if not self.sent_lka_steering_cmd and self.CP.networkLocation == NetworkLocation.fwdCamera: if init_lka_counter:
self.lka_steering_cmd_counter = CS.camera_lka_steering_cmd_counter + 1 self.lka_steering_cmd_counter = CS.camera_lka_steering_cmd_counter + 1
if CC.latActive: if CC.latActive:
@ -59,6 +70,7 @@ class CarController:
else: else:
apply_steer = 0 apply_steer = 0
self.last_steer_frame = self.frame
self.apply_steer_last = apply_steer self.apply_steer_last = apply_steer
idx = self.lka_steering_cmd_counter % 4 idx = self.lka_steering_cmd_counter % 4
can_sends.append(gmcan.create_steering_control(self.packer_pt, CanBus.POWERTRAIN, apply_steer, idx, CC.latActive)) can_sends.append(gmcan.create_steering_control(self.packer_pt, CanBus.POWERTRAIN, apply_steer, idx, CC.latActive))
@ -67,8 +79,8 @@ class CarController:
# Gas/regen, brakes, and UI commands - all at 25Hz # Gas/regen, brakes, and UI commands - all at 25Hz
if self.frame % 4 == 0: if self.frame % 4 == 0:
if not CC.longActive: if not CC.longActive:
# Stock ECU sends max regen when not enabled # ASCM sends max regen when not enabled
self.apply_gas = self.params.MAX_ACC_REGEN self.apply_gas = self.params.INACTIVE_REGEN
self.apply_brake = 0 self.apply_brake = 0
else: else:
if self.CP.carFingerprint in EV_CAR: if self.CP.carFingerprint in EV_CAR:
@ -111,12 +123,21 @@ class CarController:
can_sends += gmcan.create_adas_keepalive(CanBus.POWERTRAIN) can_sends += gmcan.create_adas_keepalive(CanBus.POWERTRAIN)
else: else:
# While car is braking, cancel button causes ECM to enter a soft disable state with a fault status.
# A delayed cancellation allows camera to cancel and avoids a fault when user depresses brake quickly
self.cancel_counter = self.cancel_counter + 1 if CC.cruiseControl.cancel else 0
# Stock longitudinal, integrated at camera # Stock longitudinal, integrated at camera
if (self.frame - self.last_button_frame) * DT_CTRL > 0.04: if (self.frame - self.last_button_frame) * DT_CTRL > 0.04:
if CC.cruiseControl.cancel: if self.cancel_counter > CAMERA_CANCEL_DELAY_FRAMES:
self.last_button_frame = self.frame self.last_button_frame = self.frame
can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.CAMERA, CS.buttons_counter, CruiseButtons.CANCEL)) can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.CAMERA, CS.buttons_counter, CruiseButtons.CANCEL))
if self.CP.networkLocation == NetworkLocation.fwdCamera:
# Silence "Take Steering" alert sent by camera, forward PSCMStatus with HandsOffSWlDetectionStatus=1
if self.frame % 10 == 0:
can_sends.append(gmcan.create_pscm_status(self.packer_pt, CanBus.CAMERA, CS.pscm_status))
# Show green icon when LKA torque is applied, and # Show green icon when LKA torque is applied, and
# alarming orange icon when approaching torque limit. # alarming orange icon when approaching torque limit.
# If not sent again, LKA icon disappears in about 5 seconds. # If not sent again, LKA icon disappears in about 5 seconds.

@ -1,3 +1,4 @@
import copy
from cereal import car from cereal import car
from common.conversions import Conversions as CV from common.conversions import Conversions as CV
from common.numpy_fast import mean from common.numpy_fast import mean
@ -8,6 +9,7 @@ from selfdrive.car.gm.values import DBC, AccState, CanBus, STEER_THRESHOLD
TransmissionType = car.CarParams.TransmissionType TransmissionType = car.CarParams.TransmissionType
NetworkLocation = car.CarParams.NetworkLocation NetworkLocation = car.CarParams.NetworkLocation
STANDSTILL_THRESHOLD = 10 * 0.0311 * CV.KPH_TO_MS
class CarState(CarStateBase): class CarState(CarStateBase):
@ -25,9 +27,10 @@ class CarState(CarStateBase):
self.prev_cruise_buttons = self.cruise_buttons self.prev_cruise_buttons = self.cruise_buttons
self.cruise_buttons = pt_cp.vl["ASCMSteeringButton"]["ACCButtons"] self.cruise_buttons = pt_cp.vl["ASCMSteeringButton"]["ACCButtons"]
self.buttons_counter = pt_cp.vl["ASCMSteeringButton"]["RollingCounter"] self.buttons_counter = pt_cp.vl["ASCMSteeringButton"]["RollingCounter"]
self.pscm_status = copy.copy(pt_cp.vl["PSCMStatus"])
# Variables used for avoiding LKAS faults # Variables used for avoiding LKAS faults
self.loopback_lka_steering_cmd_updated = len(loopback_cp.vl_all["ASCMLKASteeringCmd"]) > 0 self.loopback_lka_steering_cmd_updated = len(loopback_cp.vl_all["ASCMLKASteeringCmd"]["RollingCounter"]) > 0
if self.CP.networkLocation == NetworkLocation.fwdCamera: if self.CP.networkLocation == NetworkLocation.fwdCamera:
self.camera_lka_steering_cmd_counter = cam_cp.vl["ASCMLKASteeringCmd"]["RollingCounter"] self.camera_lka_steering_cmd_counter = cam_cp.vl["ASCMLKASteeringCmd"]["RollingCounter"]
@ -39,7 +42,8 @@ class CarState(CarStateBase):
) )
ret.vEgoRaw = mean([ret.wheelSpeeds.fl, ret.wheelSpeeds.fr, ret.wheelSpeeds.rl, ret.wheelSpeeds.rr]) ret.vEgoRaw = mean([ret.wheelSpeeds.fl, ret.wheelSpeeds.fr, ret.wheelSpeeds.rl, ret.wheelSpeeds.rr])
ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw) ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw)
ret.standstill = ret.vEgoRaw < 0.01 # sample rear wheel speeds, standstill=True if ECM allows engagement with brake
ret.standstill = ret.wheelSpeeds.rl <= STANDSTILL_THRESHOLD and ret.wheelSpeeds.rr <= STANDSTILL_THRESHOLD
if pt_cp.vl["ECMPRDNL2"]["ManualMode"] == 1: if pt_cp.vl["ECMPRDNL2"]["ManualMode"] == 1:
ret.gearShifter = self.parse_gear_shifter("T") ret.gearShifter = self.parse_gear_shifter("T")
@ -51,12 +55,7 @@ class CarState(CarStateBase):
# To avoid a cruise fault we need to match the ECM's brake pressed signal and threshold # To avoid a cruise fault we need to match the ECM's brake pressed signal and threshold
# https://static.nhtsa.gov/odi/tsbs/2017/MC-10137629-9999.pdf # https://static.nhtsa.gov/odi/tsbs/2017/MC-10137629-9999.pdf
ret.brake = pt_cp.vl["ECMAcceleratorPos"]["BrakePedalPos"] ret.brake = pt_cp.vl["ECMAcceleratorPos"]["BrakePedalPos"]
if self.CP.networkLocation != NetworkLocation.fwdCamera: ret.brakePressed = ret.brake >= 8
ret.brakePressed = ret.brake >= 8
else:
# While car is braking, cancel button causes ECM to enter a soft disable state with a fault status.
# Match ECM threshold at a standstill to allow the camera to cancel earlier
ret.brakePressed = ret.brake >= 20
# Regen braking is braking # Regen braking is braking
if self.CP.transmissionType == TransmissionType.direct: if self.CP.transmissionType == TransmissionType.direct:
@ -96,9 +95,7 @@ class CarState(CarStateBase):
ret.cruiseState.standstill = pt_cp.vl["AcceleratorPedal2"]["CruiseState"] == AccState.STANDSTILL ret.cruiseState.standstill = pt_cp.vl["AcceleratorPedal2"]["CruiseState"] == AccState.STANDSTILL
if self.CP.networkLocation == NetworkLocation.fwdCamera: if self.CP.networkLocation == NetworkLocation.fwdCamera:
ret.cruiseState.speed = cam_cp.vl["ASCMActiveCruiseControlStatus"]["ACCSpeedSetpoint"] * CV.KPH_TO_MS ret.cruiseState.speed = cam_cp.vl["ASCMActiveCruiseControlStatus"]["ACCSpeedSetpoint"] * CV.KPH_TO_MS
ret.stockAeb = cam_cp.vl["AEBCmd"]["AEBCmdActive"] != 0 ret.stockAeb = cam_cp.vl["AEBCmd"]["AEBCmdActive"] != 0
ret.stockFcw = cam_cp.vl["ASCMActiveCruiseControlStatus"]["FCWAlert"] != 0
return ret return ret
@ -110,7 +107,6 @@ class CarState(CarStateBase):
signals += [ signals += [
("AEBCmdActive", "AEBCmd"), ("AEBCmdActive", "AEBCmd"),
("RollingCounter", "ASCMLKASteeringCmd"), ("RollingCounter", "ASCMLKASteeringCmd"),
("FCWAlert", "ASCMActiveCruiseControlStatus"),
("ACCSpeedSetpoint", "ASCMActiveCruiseControlStatus"), ("ACCSpeedSetpoint", "ASCMActiveCruiseControlStatus"),
] ]
checks += [ checks += [
@ -148,6 +144,11 @@ class CarState(CarStateBase):
("LKADriverAppldTrq", "PSCMStatus"), ("LKADriverAppldTrq", "PSCMStatus"),
("LKATorqueDelivered", "PSCMStatus"), ("LKATorqueDelivered", "PSCMStatus"),
("LKATorqueDeliveredStatus", "PSCMStatus"), ("LKATorqueDeliveredStatus", "PSCMStatus"),
("HandsOffSWlDetectionStatus", "PSCMStatus"),
("HandsOffSWDetectionMode", "PSCMStatus"),
("LKATotalTorqueDelivered", "PSCMStatus"),
("PSCMStatusChecksum", "PSCMStatus"),
("RollingCounter", "PSCMStatus"),
("TractionControlOn", "ESPStatus"), ("TractionControlOn", "ESPStatus"),
("ParkBrake", "VehicleIgnitionAlt"), ("ParkBrake", "VehicleIgnitionAlt"),
("CruiseMainOn", "ECMEngineStatus"), ("CruiseMainOn", "ECMEngineStatus"),

@ -1,5 +1,6 @@
from selfdrive.car import make_can_msg from selfdrive.car import make_can_msg
def create_buttons(packer, bus, idx, button): def create_buttons(packer, bus, idx, button):
values = { values = {
"ACCButtons": button, "ACCButtons": button,
@ -7,8 +8,15 @@ def create_buttons(packer, bus, idx, button):
} }
return packer.make_can_msg("ASCMSteeringButton", bus, values) return packer.make_can_msg("ASCMSteeringButton", bus, values)
def create_steering_control(packer, bus, apply_steer, idx, lkas_active):
def create_pscm_status(packer, bus, pscm_status):
checksum_mod = int(1 - pscm_status["HandsOffSWlDetectionStatus"]) << 5
pscm_status["HandsOffSWlDetectionStatus"] = 1
pscm_status["PSCMStatusChecksum"] += checksum_mod
return packer.make_can_msg("PSCMStatus", bus, pscm_status)
def create_steering_control(packer, bus, apply_steer, idx, lkas_active):
values = { values = {
"LKASteeringCmdActive": lkas_active, "LKASteeringCmdActive": lkas_active,
"LKASteeringCmd": apply_steer, "LKASteeringCmd": apply_steer,
@ -18,15 +26,17 @@ def create_steering_control(packer, bus, apply_steer, idx, lkas_active):
return packer.make_can_msg("ASCMLKASteeringCmd", bus, values) return packer.make_can_msg("ASCMLKASteeringCmd", bus, values)
def create_adas_keepalive(bus): def create_adas_keepalive(bus):
dat = b"\x00\x00\x00\x00\x00\x00\x00" dat = b"\x00\x00\x00\x00\x00\x00\x00"
return [make_can_msg(0x409, dat, bus), make_can_msg(0x40a, dat, bus)] return [make_can_msg(0x409, dat, bus), make_can_msg(0x40a, dat, bus)]
def create_gas_regen_command(packer, bus, throttle, idx, acc_engaged, at_full_stop):
def create_gas_regen_command(packer, bus, throttle, idx, enabled, at_full_stop):
values = { values = {
"GasRegenCmdActive": acc_engaged, "GasRegenCmdActive": enabled,
"RollingCounter": idx, "RollingCounter": idx,
"GasRegenCmdActiveInv": 1 - acc_engaged, "GasRegenCmdActiveInv": 1 - enabled,
"GasRegenCmd": throttle, "GasRegenCmd": throttle,
"GasRegenFullStopActive": at_full_stop, "GasRegenFullStopActive": at_full_stop,
"GasRegenAlwaysOne": 1, "GasRegenAlwaysOne": 1,
@ -41,6 +51,7 @@ def create_gas_regen_command(packer, bus, throttle, idx, acc_engaged, at_full_st
return packer.make_can_msg("ASCMGasRegenCmd", bus, values) return packer.make_can_msg("ASCMGasRegenCmd", bus, values)
def create_friction_brake_command(packer, bus, apply_brake, idx, near_stop, at_full_stop): def create_friction_brake_command(packer, bus, apply_brake, idx, near_stop, at_full_stop):
mode = 0x1 mode = 0x1
if apply_brake > 0: if apply_brake > 0:
@ -57,44 +68,48 @@ def create_friction_brake_command(packer, bus, apply_brake, idx, near_stop, at_f
checksum = (0x10000 - (mode << 12) - brake - idx) & 0xffff checksum = (0x10000 - (mode << 12) - brake - idx) & 0xffff
values = { values = {
"RollingCounter" : idx, "RollingCounter": idx,
"FrictionBrakeMode" : mode, "FrictionBrakeMode": mode,
"FrictionBrakeChecksum": checksum, "FrictionBrakeChecksum": checksum,
"FrictionBrakeCmd" : -apply_brake "FrictionBrakeCmd": -apply_brake
} }
return packer.make_can_msg("EBCMFrictionBrakeCmd", bus, values) return packer.make_can_msg("EBCMFrictionBrakeCmd", bus, values)
def create_acc_dashboard_command(packer, bus, acc_engaged, target_speed_kph, lead_car_in_sight, fcw):
def create_acc_dashboard_command(packer, bus, enabled, target_speed_kph, lead_car_in_sight, fcw):
target_speed = min(target_speed_kph, 255) target_speed = min(target_speed_kph, 255)
values = { values = {
"ACCAlwaysOne" : 1, "ACCAlwaysOne": 1,
"ACCResumeButton" : 0, "ACCResumeButton": 0,
"ACCSpeedSetpoint" : target_speed, "ACCSpeedSetpoint": target_speed,
"ACCGapLevel" : 3 * acc_engaged, # 3 "far", 0 "inactive" "ACCGapLevel": 3 * enabled, # 3 "far", 0 "inactive"
"ACCCmdActive" : acc_engaged, "ACCCmdActive": enabled,
"ACCAlwaysOne2" : 1, "ACCAlwaysOne2": 1,
"ACCLeadCar" : lead_car_in_sight, "ACCLeadCar": lead_car_in_sight,
"FCWAlert": 0x3 if fcw else 0 "FCWAlert": 0x3 if fcw else 0
} }
return packer.make_can_msg("ASCMActiveCruiseControlStatus", bus, values) return packer.make_can_msg("ASCMActiveCruiseControlStatus", bus, values)
def create_adas_time_status(bus, tt, idx): def create_adas_time_status(bus, tt, idx):
dat = [(tt >> 20) & 0xff, (tt >> 12) & 0xff, (tt >> 4) & 0xff, dat = [(tt >> 20) & 0xff, (tt >> 12) & 0xff, (tt >> 4) & 0xff,
((tt & 0xf) << 4) + (idx << 2)] ((tt & 0xf) << 4) + (idx << 2)]
chksum = 0x1000 - dat[0] - dat[1] - dat[2] - dat[3] chksum = 0x1000 - dat[0] - dat[1] - dat[2] - dat[3]
chksum = chksum & 0xfff chksum = chksum & 0xfff
dat += [0x40 + (chksum >> 8), chksum & 0xff, 0x12] dat += [0x40 + (chksum >> 8), chksum & 0xff, 0x12]
return make_can_msg(0xa1, bytes(dat), bus) return make_can_msg(0xa1, bytes(dat), bus)
def create_adas_steering_status(bus, idx): def create_adas_steering_status(bus, idx):
dat = [idx << 6, 0xf0, 0x20, 0, 0, 0] dat = [idx << 6, 0xf0, 0x20, 0, 0, 0]
chksum = 0x60 + sum(dat) chksum = 0x60 + sum(dat)
dat += [chksum >> 8, chksum & 0xff] dat += [chksum >> 8, chksum & 0xff]
return make_can_msg(0x306, bytes(dat), bus) return make_can_msg(0x306, bytes(dat), bus)
def create_adas_accelerometer_speed_status(bus, speed_ms, idx): def create_adas_accelerometer_speed_status(bus, speed_ms, idx):
spd = int(speed_ms * 16) & 0xfff spd = int(speed_ms * 16) & 0xfff
accel = 0 & 0xfff accel = 0 & 0xfff
@ -108,6 +123,7 @@ def create_adas_accelerometer_speed_status(bus, speed_ms, idx):
dat += [(idx << 5) + (far_range_mode << 4) + (near_range_mode << 3) + (chksum >> 8), chksum & 0xff] dat += [(idx << 5) + (far_range_mode << 4) + (near_range_mode << 3) + (chksum >> 8), chksum & 0xff]
return make_can_msg(0x308, bytes(dat), bus) return make_can_msg(0x308, bytes(dat), bus)
def create_adas_headlights_status(packer, bus): def create_adas_headlights_status(packer, bus):
values = { values = {
"Always42": 0x42, "Always42": 0x42,
@ -115,6 +131,7 @@ def create_adas_headlights_status(packer, bus):
} }
return packer.make_can_msg("ASCMHeadlight", bus, values) return packer.make_can_msg("ASCMHeadlight", bus, values)
def create_lka_icon_command(bus, active, critical, steer): def create_lka_icon_command(bus, active, critical, steer):
if active and steer == 1: if active and steer == 1:
if critical: if critical:

@ -62,11 +62,14 @@ class CarInterface(CarInterfaceBase):
ret.radarOffCan = True # no radar ret.radarOffCan = True # no radar
ret.pcmCruise = True ret.pcmCruise = True
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM
ret.minEnableSpeed = 5 * CV.KPH_TO_MS
else: # ASCM, OBD-II harness else: # ASCM, OBD-II harness
ret.openpilotLongitudinalControl = True ret.openpilotLongitudinalControl = True
ret.networkLocation = NetworkLocation.gateway ret.networkLocation = NetworkLocation.gateway
ret.radarOffCan = False ret.radarOffCan = False
ret.pcmCruise = False # stock non-adaptive cruise control is kept off ret.pcmCruise = False # stock non-adaptive cruise control is kept off
# supports stop and go, but initial engage must (conservatively) be above 18mph
ret.minEnableSpeed = 18 * CV.MPH_TO_MS
# These cars have been put into dashcam only due to both a lack of users and test coverage. # These cars have been put into dashcam only due to both a lack of users and test coverage.
# These cars likely still work fine. Once a user confirms each car works and a test route is # These cars likely still work fine. Once a user confirms each car works and a test route is
@ -90,9 +93,6 @@ class CarInterface(CarInterfaceBase):
ret.steerLimitTimer = 0.4 ret.steerLimitTimer = 0.4
ret.radarTimeStep = 0.0667 # GM radar runs at 15Hz instead of standard 20Hz ret.radarTimeStep = 0.0667 # GM radar runs at 15Hz instead of standard 20Hz
# supports stop and go, but initial engage must (conservatively) be above 18mph
ret.minEnableSpeed = 18 * CV.MPH_TO_MS
if candidate == CAR.VOLT: if candidate == CAR.VOLT:
ret.mass = 1607. + STD_CARGO_KG ret.mass = 1607. + STD_CARGO_KG
ret.wheelbase = 2.69 ret.wheelbase = 2.69
@ -153,7 +153,6 @@ class CarInterface(CarInterfaceBase):
tire_stiffness_factor = 1.0 tire_stiffness_factor = 1.0
elif candidate in (CAR.BOLT_EV, CAR.BOLT_EUV): elif candidate in (CAR.BOLT_EV, CAR.BOLT_EUV):
ret.minEnableSpeed = -1
ret.mass = 1669. + STD_CARGO_KG ret.mass = 1669. + STD_CARGO_KG
ret.wheelbase = 2.63779 ret.wheelbase = 2.63779
ret.steerRatio = 16.8 ret.steerRatio = 16.8
@ -163,7 +162,6 @@ class CarInterface(CarInterfaceBase):
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.SILVERADO: elif candidate == CAR.SILVERADO:
ret.minEnableSpeed = -1
ret.mass = 2200. + STD_CARGO_KG ret.mass = 2200. + STD_CARGO_KG
ret.wheelbase = 3.75 ret.wheelbase = 3.75
ret.steerRatio = 16.3 ret.steerRatio = 16.3
@ -172,7 +170,6 @@ class CarInterface(CarInterfaceBase):
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.EQUINOX: elif candidate == CAR.EQUINOX:
ret.minEnableSpeed = -1
ret.mass = 3500. * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 3500. * CV.LB_TO_KG + STD_CARGO_KG
ret.wheelbase = 2.72 ret.wheelbase = 2.72
ret.steerRatio = 14.4 ret.steerRatio = 14.4
@ -207,19 +204,16 @@ class CarInterface(CarInterfaceBase):
GearShifter.eco, GearShifter.manumatic], GearShifter.eco, GearShifter.manumatic],
pcm_enable=self.CP.pcmCruise) pcm_enable=self.CP.pcmCruise)
if ret.vEgo < self.CP.minEnableSpeed: # Enabling at a standstill with brake is allowed
# TODO: verify 17 Volt can enable for the first time at a stop and allow for all GMs
if ret.vEgo < self.CP.minEnableSpeed and not (ret.standstill and ret.brake >= 20 and
self.CP.networkLocation == NetworkLocation.fwdCamera):
events.add(EventName.belowEngageSpeed) events.add(EventName.belowEngageSpeed)
if ret.cruiseState.standstill: if ret.cruiseState.standstill:
events.add(EventName.resumeRequired) events.add(EventName.resumeRequired)
if ret.vEgo < self.CP.minSteerSpeed: if ret.vEgo < self.CP.minSteerSpeed:
events.add(EventName.belowSteerSpeed) events.add(EventName.belowSteerSpeed)
if self.CP.networkLocation == NetworkLocation.fwdCamera and self.CP.pcmCruise:
# The ECM has a higher brake pressed threshold than the camera, causing an
# ACC fault when you engage at a stop with your foot partially on the brake
if ret.vEgoRaw < 0.1 and ret.brake < 20:
events.add(EventName.gmAccFaultedTemp)
ret.events = events.to_msg() ret.events = events.to_msg()
return ret return ret

@ -11,7 +11,8 @@ Ecu = car.CarParams.Ecu
class CarControllerParams: class CarControllerParams:
STEER_MAX = 300 # GM limit is 3Nm. Used by carcontroller to generate LKA output STEER_MAX = 300 # GM limit is 3Nm. Used by carcontroller to generate LKA output
STEER_STEP = 2 # Control frames per command (50hz) ACTIVE_STEER_STEP = 2 # Active control frames per command (50hz)
INACTIVE_STEER_STEP = 10 # Inactive control frames per command (10hz)
STEER_DELTA_UP = 7 # Delta rates require review due to observed EPS weakness STEER_DELTA_UP = 7 # Delta rates require review due to observed EPS weakness
STEER_DELTA_DOWN = 17 STEER_DELTA_DOWN = 17
STEER_DRIVER_ALLOWANCE = 50 STEER_DRIVER_ALLOWANCE = 50
@ -30,6 +31,7 @@ class CarControllerParams:
ZERO_GAS = 2048 # Coasting ZERO_GAS = 2048 # Coasting
MAX_BRAKE = 400 # ~ -4.0 m/s^2 with regen MAX_BRAKE = 400 # ~ -4.0 m/s^2 with regen
MAX_ACC_REGEN = 1404 # Max ACC regen is slightly less than max paddle regen MAX_ACC_REGEN = 1404 # Max ACC regen is slightly less than max paddle regen
INACTIVE_REGEN = 1404
# Allow small margin below -3.5 m/s^2 from ISO 15622:2018 since we # Allow small margin below -3.5 m/s^2 from ISO 15622:2018 since we
# perform the closed loop control, and might need some # perform the closed loop control, and might need some

@ -105,7 +105,6 @@ class Footnote(Enum):
@dataclass @dataclass
class HondaCarInfo(CarInfo): class HondaCarInfo(CarInfo):
package: str = "Honda Sensing" package: str = "Honda Sensing"
min_steer_speed: float = 12. * CV.MPH_TO_MS
CAR_INFO: Dict[str, Optional[Union[HondaCarInfo, List[HondaCarInfo]]]] = { CAR_INFO: Dict[str, Optional[Union[HondaCarInfo, List[HondaCarInfo]]]] = {
@ -114,31 +113,31 @@ CAR_INFO: Dict[str, Optional[Union[HondaCarInfo, List[HondaCarInfo]]]] = {
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", min_steer_speed=12. * CV.MPH_TO_MS, harness=Harness.nidec, video_link="https://youtu.be/-IkImTe1NYE"),
CAR.CIVIC_BOSCH: [ CAR.CIVIC_BOSCH: [
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 2019-21", "All", "https://www.youtube.com/watch?v=4Iz1Mz5LGF8", [Footnote.CIVIC_DIESEL], 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", min_steer_speed=12. * CV.MPH_TO_MS, harness=Harness.bosch_a),
], ],
CAR.CIVIC_BOSCH_DIESEL: None, # same platform CAR.CIVIC_BOSCH_DIESEL: None, # same platform
CAR.CIVIC_2022: [ CAR.CIVIC_2022: [
HondaCarInfo("Honda Civic 2022", "All", min_steer_speed=0., harness=Harness.bosch_b), HondaCarInfo("Honda Civic 2022", "All", harness=Harness.bosch_b),
HondaCarInfo("Honda Civic Hatchback 2022", "All", min_steer_speed=0., harness=Harness.bosch_b), HondaCarInfo("Honda Civic Hatchback 2022", "All", harness=Harness.bosch_b),
], ],
CAR.ACURA_ILX: HondaCarInfo("Acura ILX 2016-19", "AcuraWatch Plus", min_steer_speed=25. * CV.MPH_TO_MS, harness=Harness.nidec), CAR.ACURA_ILX: HondaCarInfo("Acura ILX 2016-19", "AcuraWatch Plus", min_steer_speed=25. * CV.MPH_TO_MS, harness=Harness.nidec),
CAR.CRV: HondaCarInfo("Honda CR-V 2015-16", "Touring Trim", harness=Harness.nidec), CAR.CRV: HondaCarInfo("Honda CR-V 2015-16", "Touring Trim", min_steer_speed=12. * CV.MPH_TO_MS, harness=Harness.nidec),
CAR.CRV_5G: HondaCarInfo("Honda CR-V 2017-22", harness=Harness.bosch_a), CAR.CRV_5G: HondaCarInfo("Honda CR-V 2017-22", min_steer_speed=12. * CV.MPH_TO_MS, harness=Harness.bosch_a),
CAR.CRV_EU: None, # HondaCarInfo("Honda CR-V EU", "Touring"), # Euro version of CRV Touring CAR.CRV_EU: None, # HondaCarInfo("Honda CR-V EU", "Touring"), # Euro version of CRV Touring
CAR.CRV_HYBRID: HondaCarInfo("Honda CR-V Hybrid 2017-19", harness=Harness.bosch_a), CAR.CRV_HYBRID: HondaCarInfo("Honda CR-V Hybrid 2017-19", min_steer_speed=12. * CV.MPH_TO_MS, harness=Harness.bosch_a),
CAR.FIT: HondaCarInfo("Honda Fit 2018-20", harness=Harness.nidec), CAR.FIT: HondaCarInfo("Honda Fit 2018-20", min_steer_speed=12. * CV.MPH_TO_MS, harness=Harness.nidec),
CAR.FREED: HondaCarInfo("Honda Freed 2020", harness=Harness.nidec), CAR.FREED: HondaCarInfo("Honda Freed 2020", min_steer_speed=12. * CV.MPH_TO_MS, harness=Harness.nidec),
CAR.HRV: HondaCarInfo("Honda HR-V 2019-22", harness=Harness.nidec), CAR.HRV: HondaCarInfo("Honda HR-V 2019-22", min_steer_speed=12. * CV.MPH_TO_MS, harness=Harness.nidec),
CAR.ODYSSEY: HondaCarInfo("Honda Odyssey 2018-20", min_steer_speed=0., harness=Harness.nidec), CAR.ODYSSEY: HondaCarInfo("Honda Odyssey 2018-20", harness=Harness.nidec),
CAR.ODYSSEY_CHN: None, # Chinese version of Odyssey CAR.ODYSSEY_CHN: None, # Chinese version of Odyssey
CAR.ACURA_RDX: HondaCarInfo("Acura RDX 2016-18", "AcuraWatch Plus", harness=Harness.nidec), CAR.ACURA_RDX: HondaCarInfo("Acura RDX 2016-18", "AcuraWatch Plus", min_steer_speed=12. * CV.MPH_TO_MS, harness=Harness.nidec),
CAR.ACURA_RDX_3G: HondaCarInfo("Acura RDX 2019-22", "All", min_steer_speed=3. * CV.MPH_TO_MS, harness=Harness.bosch_a), CAR.ACURA_RDX_3G: HondaCarInfo("Acura RDX 2019-22", "All", min_steer_speed=3. * CV.MPH_TO_MS, harness=Harness.bosch_a),
CAR.PILOT: HondaCarInfo("Honda Pilot 2016-22", harness=Harness.nidec), CAR.PILOT: HondaCarInfo("Honda Pilot 2016-22", min_steer_speed=12. * CV.MPH_TO_MS, harness=Harness.nidec),
CAR.PASSPORT: HondaCarInfo("Honda Passport 2019-21", "All", harness=Harness.nidec), CAR.PASSPORT: HondaCarInfo("Honda Passport 2019-21", "All", min_steer_speed=12. * CV.MPH_TO_MS, harness=Harness.nidec),
CAR.RIDGELINE: HondaCarInfo("Honda Ridgeline 2017-22", harness=Harness.nidec), CAR.RIDGELINE: HondaCarInfo("Honda Ridgeline 2017-22", min_steer_speed=12. * CV.MPH_TO_MS, harness=Harness.nidec),
CAR.INSIGHT: HondaCarInfo("Honda Insight 2019-22", "All", min_steer_speed=3. * CV.MPH_TO_MS, harness=Harness.bosch_a), CAR.INSIGHT: HondaCarInfo("Honda Insight 2019-22", "All", min_steer_speed=3. * CV.MPH_TO_MS, harness=Harness.bosch_a),
CAR.HONDA_E: HondaCarInfo("Honda e 2020", "All", min_steer_speed=3. * CV.MPH_TO_MS, harness=Harness.bosch_a), CAR.HONDA_E: HondaCarInfo("Honda e 2020", "All", min_steer_speed=3. * CV.MPH_TO_MS, harness=Harness.bosch_a),
} }
@ -447,7 +446,7 @@ FW_VERSIONS = {
b'78109-TED-Q510\x00\x00', b'78109-TED-Q510\x00\x00',
b'78109-TEG-A310\x00\x00', b'78109-TEG-A310\x00\x00',
], ],
(Ecu.fwdCamera, 0x18dab0f1, None): [ (Ecu.fwdRadar, 0x18dab0f1, None): [
b'36161-TBA-A020\x00\x00', b'36161-TBA-A020\x00\x00',
b'36161-TBA-A030\x00\x00', b'36161-TBA-A030\x00\x00',
b'36161-TBA-A040\x00\x00', b'36161-TBA-A040\x00\x00',
@ -965,7 +964,7 @@ FW_VERSIONS = {
b'77959-THR-A110\x00\x00', b'77959-THR-A110\x00\x00',
b'77959-THR-X010\x00\x00', b'77959-THR-X010\x00\x00',
], ],
(Ecu.fwdCamera, 0x18dab0f1, None): [ (Ecu.fwdRadar, 0x18dab0f1, None): [
b'36161-THR-A020\x00\x00', b'36161-THR-A020\x00\x00',
b'36161-THR-A030\x00\x00', b'36161-THR-A030\x00\x00',
b'36161-THR-A110\x00\x00', b'36161-THR-A110\x00\x00',
@ -1069,7 +1068,7 @@ FW_VERSIONS = {
b'39990-TG7-A070\x00\x00', b'39990-TG7-A070\x00\x00',
b'39990-TGS-A230\x00\x00', b'39990-TGS-A230\x00\x00',
], ],
(Ecu.fwdCamera, 0x18dab0f1, None): [ (Ecu.fwdRadar, 0x18dab0f1, None): [
b'36161-TG7-A310\x00\x00', b'36161-TG7-A310\x00\x00',
b'36161-TG7-A520\x00\x00', b'36161-TG7-A520\x00\x00',
b'36161-TG7-A630\x00\x00', b'36161-TG7-A630\x00\x00',
@ -1177,7 +1176,7 @@ FW_VERSIONS = {
b'57114-TX5-A220\x00\x00', b'57114-TX5-A220\x00\x00',
b'57114-TX4-A220\x00\x00', b'57114-TX4-A220\x00\x00',
], ],
(Ecu.fwdCamera, 0x18dab0f1, None): [ (Ecu.fwdRadar, 0x18dab0f1, None): [
b'36161-TX5-A030\x00\x00', b'36161-TX5-A030\x00\x00',
b'36161-TX4-A030\x00\x00', b'36161-TX4-A030\x00\x00',
], ],
@ -1274,7 +1273,7 @@ FW_VERSIONS = {
b'39990-T6Z-A030\x00\x00', b'39990-T6Z-A030\x00\x00',
b'39990-T6Z-A050\x00\x00', b'39990-T6Z-A050\x00\x00',
], ],
(Ecu.fwdCamera, 0x18dab0f1, None): [ (Ecu.fwdRadar, 0x18dab0f1, None): [
b'36161-T6Z-A020\x00\x00', b'36161-T6Z-A020\x00\x00',
b'36161-T6Z-A310\x00\x00', b'36161-T6Z-A310\x00\x00',
b'36161-T6Z-A420\x00\x00', b'36161-T6Z-A420\x00\x00',

@ -90,13 +90,27 @@ class CarController:
addr, bus = 0x730, 5 addr, bus = 0x730, 5
can_sends.append([addr, 0, b"\x02\x3E\x80\x00\x00\x00\x00\x00", bus]) can_sends.append([addr, 0, b"\x02\x3E\x80\x00\x00\x00\x00\x00", bus])
# >90 degree steering fault prevention
# Count up to MAX_ANGLE_FRAMES, at which point we need to cut torque to avoid a steering fault
if CC.latActive and abs(CS.out.steeringAngleDeg) >= MAX_ANGLE:
self.angle_limit_counter += 1
else:
self.angle_limit_counter = 0
# Cut steer actuation bit for two frames and hold torque with induced temporary fault
torque_fault = CC.latActive and self.angle_limit_counter > MAX_ANGLE_FRAMES
lat_active = CC.latActive and not torque_fault
if self.angle_limit_counter >= MAX_ANGLE_FRAMES + MAX_ANGLE_CONSECUTIVE_FRAMES:
self.angle_limit_counter = 0
# CAN-FD platforms # CAN-FD platforms
if self.CP.carFingerprint in CANFD_CAR: if self.CP.carFingerprint in CANFD_CAR:
hda2 = self.CP.flags & HyundaiFlags.CANFD_HDA2 hda2 = self.CP.flags & HyundaiFlags.CANFD_HDA2
hda2_long = hda2 and self.CP.openpilotLongitudinalControl hda2_long = hda2 and self.CP.openpilotLongitudinalControl
# steering control # steering control
can_sends.extend(hyundaicanfd.create_steering_messages(self.packer, self.CP, CC.enabled, CC.latActive, apply_steer)) can_sends.extend(hyundaicanfd.create_steering_messages(self.packer, self.CP, CC.enabled, lat_active, apply_steer))
# disable LFA on HDA2 # disable LFA on HDA2
if self.frame % 5 == 0 and hda2: if self.frame % 5 == 0 and hda2:
@ -121,29 +135,19 @@ class CarController:
self.last_button_frame = self.frame self.last_button_frame = self.frame
else: else:
for _ in range(20): for _ in range(20):
can_sends.append(hyundaicanfd.create_buttons(self.packer, CS.buttons_counter+1, Buttons.CANCEL)) can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, CS.buttons_counter+1, Buttons.CANCEL))
self.last_button_frame = self.frame self.last_button_frame = self.frame
# cruise standstill resume # cruise standstill resume
elif CC.cruiseControl.resume: elif CC.cruiseControl.resume:
if not (self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS): if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
# TODO: resume for alt button cars
pass
else:
for _ in range(20): for _ in range(20):
can_sends.append(hyundaicanfd.create_buttons(self.packer, CS.buttons_counter+1, Buttons.RES_ACCEL)) can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, CS.buttons_counter+1, Buttons.RES_ACCEL))
self.last_button_frame = self.frame self.last_button_frame = self.frame
else: else:
# Count up to MAX_ANGLE_FRAMES, at which point we need to cut torque to avoid a steering fault
if CC.latActive and abs(CS.out.steeringAngleDeg) >= MAX_ANGLE:
self.angle_limit_counter += 1
else:
self.angle_limit_counter = 0
# Cut steer actuation bit for two frames and hold torque with induced temporary fault
torque_fault = CC.latActive and self.angle_limit_counter > MAX_ANGLE_FRAMES
lat_active = CC.latActive and not torque_fault
if self.angle_limit_counter >= MAX_ANGLE_FRAMES + MAX_ANGLE_CONSECUTIVE_FRAMES:
self.angle_limit_counter = 0
can_sends.append(hyundaican.create_lkas11(self.packer, self.frame, self.car_fingerprint, apply_steer, lat_active, can_sends.append(hyundaican.create_lkas11(self.packer, self.frame, self.car_fingerprint, apply_steer, lat_active,
torque_fault, CS.lkas11, sys_warning, sys_state, CC.enabled, torque_fault, CS.lkas11, sys_warning, sys_state, CC.enabled,
hud_control.leftLaneVisible, hud_control.rightLaneVisible, hud_control.leftLaneVisible, hud_control.rightLaneVisible,

@ -159,7 +159,7 @@ class CarState(CarStateBase):
elif self.CP.carFingerprint in HYBRID_CAR: elif self.CP.carFingerprint in HYBRID_CAR:
ret.gas = cp.vl["ACCELERATOR_ALT"]["ACCELERATOR_PEDAL"] / 1023. ret.gas = cp.vl["ACCELERATOR_ALT"]["ACCELERATOR_PEDAL"] / 1023.
ret.gasPressed = ret.gas > 1e-5 ret.gasPressed = ret.gas > 1e-5
ret.brakePressed = cp.vl["BRAKE"]["BRAKE_PRESSED"] == 1 ret.brakePressed = cp.vl["TCS"]["DriverBraking"] == 1
ret.doorOpen = cp.vl["DOORS_SEATBELTS"]["DRIVER_DOOR_OPEN"] == 1 ret.doorOpen = cp.vl["DOORS_SEATBELTS"]["DRIVER_DOOR_OPEN"] == 1
ret.seatbeltUnlatched = cp.vl["DOORS_SEATBELTS"]["DRIVER_SEATBELT_LATCHED"] == 0 ret.seatbeltUnlatched = cp.vl["DOORS_SEATBELTS"]["DRIVER_SEATBELT_LATCHED"] == 0
@ -187,15 +187,18 @@ class CarState(CarStateBase):
ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_lamp(50, cp.vl["BLINKERS"]["LEFT_LAMP"], ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_lamp(50, cp.vl["BLINKERS"]["LEFT_LAMP"],
cp.vl["BLINKERS"]["RIGHT_LAMP"]) cp.vl["BLINKERS"]["RIGHT_LAMP"])
if self.CP.enableBsm:
ret.leftBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FL_INDICATOR"] != 0
ret.rightBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FR_INDICATOR"] != 0
ret.cruiseState.available = True ret.cruiseState.available = True
ret.cruiseState.enabled = cp.vl["SCC1"]["CRUISE_ACTIVE"] == 1
self.is_metric = cp.vl["CLUSTER_INFO"]["DISTANCE_UNIT"] != 1 self.is_metric = cp.vl["CLUSTER_INFO"]["DISTANCE_UNIT"] != 1
if not self.CP.openpilotLongitudinalControl: if not self.CP.openpilotLongitudinalControl:
speed_factor = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS speed_factor = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS
cp_cruise_info = cp if self.CP.flags & HyundaiFlags.CANFD_HDA2 else cp_cam cp_cruise_info = cp if self.CP.flags & HyundaiFlags.CANFD_HDA2 else cp_cam
ret.cruiseState.speed = cp_cruise_info.vl["CRUISE_INFO"]["SET_SPEED"] * speed_factor ret.cruiseState.speed = cp_cruise_info.vl["CRUISE_INFO"]["SET_SPEED"] * speed_factor
ret.cruiseState.standstill = cp_cruise_info.vl["CRUISE_INFO"]["CRUISE_STANDSTILL"] == 1 ret.cruiseState.standstill = cp_cruise_info.vl["CRUISE_INFO"]["CRUISE_STANDSTILL"] == 1
ret.cruiseState.enabled = cp_cruise_info.vl["CRUISE_INFO"]["CRUISE_STATUS"] != 0
self.cruise_info = copy.copy(cp_cruise_info.vl["CRUISE_INFO"]) self.cruise_info = copy.copy(cp_cruise_info.vl["CRUISE_INFO"])
cruise_btn_msg = "CRUISE_BUTTONS_ALT" if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS else "CRUISE_BUTTONS" cruise_btn_msg = "CRUISE_BUTTONS_ALT" if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS else "CRUISE_BUTTONS"
@ -415,7 +418,6 @@ class CarState(CarStateBase):
("WHEEL_SPEED_4", "WHEEL_SPEEDS"), ("WHEEL_SPEED_4", "WHEEL_SPEEDS"),
("GEAR", "GEAR_SHIFTER"), ("GEAR", "GEAR_SHIFTER"),
("BRAKE_PRESSED", "BRAKE"),
("STEERING_RATE", "STEERING_SENSORS"), ("STEERING_RATE", "STEERING_SENSORS"),
("STEERING_ANGLE", "STEERING_SENSORS"), ("STEERING_ANGLE", "STEERING_SENSORS"),
@ -423,7 +425,8 @@ class CarState(CarStateBase):
("STEERING_OUT_TORQUE", "MDPS"), ("STEERING_OUT_TORQUE", "MDPS"),
("LKA_FAULT", "MDPS"), ("LKA_FAULT", "MDPS"),
("CRUISE_ACTIVE", "SCC1"), ("DriverBraking", "TCS"),
("COUNTER", cruise_btn_msg), ("COUNTER", cruise_btn_msg),
("CRUISE_BUTTONS", cruise_btn_msg), ("CRUISE_BUTTONS", cruise_btn_msg),
("ADAPTIVE_CRUISE_MAIN_BTN", cruise_btn_msg), ("ADAPTIVE_CRUISE_MAIN_BTN", cruise_btn_msg),
@ -443,15 +446,25 @@ class CarState(CarStateBase):
("BRAKE", 100), ("BRAKE", 100),
("STEERING_SENSORS", 100), ("STEERING_SENSORS", 100),
("MDPS", 100), ("MDPS", 100),
("SCC1", 50), ("TCS", 50),
(cruise_btn_msg, 50), (cruise_btn_msg, 50),
("CLUSTER_INFO", 4), ("CLUSTER_INFO", 4),
("BLINKERS", 4), ("BLINKERS", 4),
("DOORS_SEATBELTS", 4), ("DOORS_SEATBELTS", 4),
] ]
if CP.enableBsm:
signals += [
("FL_INDICATOR", "BLINDSPOTS_REAR_CORNERS"),
("FR_INDICATOR", "BLINDSPOTS_REAR_CORNERS"),
]
checks += [
("BLINDSPOTS_REAR_CORNERS", 20),
]
if CP.flags & HyundaiFlags.CANFD_HDA2 and not CP.openpilotLongitudinalControl: if CP.flags & HyundaiFlags.CANFD_HDA2 and not CP.openpilotLongitudinalControl:
signals += [ signals += [
("CRUISE_STATUS", "CRUISE_INFO"),
("SET_SPEED", "CRUISE_INFO"), ("SET_SPEED", "CRUISE_INFO"),
("CRUISE_STANDSTILL", "CRUISE_INFO"), ("CRUISE_STANDSTILL", "CRUISE_INFO"),
] ]

@ -3,7 +3,7 @@ from selfdrive.car.hyundai.values import HyundaiFlags
def get_e_can_bus(CP): def get_e_can_bus(CP):
# On the CAN-FD platforms, the LKAS camera is on both A-CAN and E-CAN. HDA2 cars # On the CAN-FD platforms, the LKAS camera is on both A-CAN and E-CAN. HDA2 cars
# have a a different harness than the HDA1 and non-HDA variants in order to split # have a different harness than the HDA1 and non-HDA variants in order to split
# a different bus, since the steering is done by different ECUs. # a different bus, since the steering is done by different ECUs.
return 5 if CP.flags & HyundaiFlags.CANFD_HDA2 else 4 return 5 if CP.flags & HyundaiFlags.CANFD_HDA2 else 4
@ -39,13 +39,15 @@ def create_cam_0x2a4(packer, camera_values):
}) })
return packer.make_can_msg("CAM_0x2a4", 4, camera_values) return packer.make_can_msg("CAM_0x2a4", 4, camera_values)
def create_buttons(packer, cnt, btn): def create_buttons(packer, CP, cnt, btn):
values = { values = {
"COUNTER": cnt, "COUNTER": cnt,
"SET_ME_1": 1, "SET_ME_1": 1,
"CRUISE_BUTTONS": btn, "CRUISE_BUTTONS": btn,
} }
return packer.make_can_msg("CRUISE_BUTTONS", 5, values)
bus = 5 if CP.flags & HyundaiFlags.CANFD_HDA2 else 6
return packer.make_can_msg("CRUISE_BUTTONS", bus, values)
def create_acc_cancel(packer, CP, cruise_info_copy): def create_acc_cancel(packer, CP, cruise_info_copy):
values = cruise_info_copy values = cruise_info_copy

@ -8,6 +8,7 @@ from selfdrive.car import STD_CARGO_KG, create_button_event, scale_rot_inertia,
from selfdrive.car.interfaces import CarInterfaceBase from selfdrive.car.interfaces import CarInterfaceBase
from selfdrive.car.disable_ecu import disable_ecu from selfdrive.car.disable_ecu import disable_ecu
Ecu = car.CarParams.Ecu
ButtonType = car.CarState.ButtonEvent.Type ButtonType = car.CarState.ButtonEvent.Type
EventName = car.CarEvent.EventName EventName = car.CarEvent.EventName
ENABLE_BUTTONS = (Buttons.RES_ACCEL, Buttons.SET_DECEL, Buttons.CANCEL) ENABLE_BUTTONS = (Buttons.RES_ACCEL, Buttons.SET_DECEL, Buttons.CANCEL)
@ -30,11 +31,11 @@ class CarInterface(CarInterfaceBase):
# These cars have been put into dashcam only due to both a lack of users and test coverage. # These cars have been put into dashcam only due to both a lack of users and test coverage.
# These cars likely still work fine. Once a user confirms each car works and a test route is # These cars likely still work fine. Once a user confirms each car works and a test route is
# added to selfdrive/car/tests/routes.py, we can remove it from this list. # added to selfdrive/car/tests/routes.py, we can remove it from this list.
ret.dashcamOnly = candidate in {CAR.KIA_OPTIMA_H, CAR.ELANTRA_GT_I30} ret.dashcamOnly = candidate in {CAR.KIA_OPTIMA_H, }
if candidate in CANFD_CAR: if candidate in CANFD_CAR:
# detect HDA2 with LKAS message # detect HDA2 with ADAS Driving ECU
if 0x50 in fingerprint[6]: if Ecu.adas in [fw.ecu for fw in car_fw]:
ret.flags |= HyundaiFlags.CANFD_HDA2.value ret.flags |= HyundaiFlags.CANFD_HDA2.value
else: else:
# non-HDA2 # non-HDA2
@ -44,141 +45,92 @@ class CarInterface(CarInterfaceBase):
ret.steerActuatorDelay = 0.1 # Default delay ret.steerActuatorDelay = 0.1 # Default delay
ret.steerLimitTimer = 0.4 ret.steerLimitTimer = 0.4
tire_stiffness_factor = 1. tire_stiffness_factor = 1.
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
if candidate in (CAR.SANTA_FE, CAR.SANTA_FE_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022): if candidate in (CAR.SANTA_FE, CAR.SANTA_FE_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022):
ret.lateralTuning.pid.kf = 0.00005
ret.mass = 3982. * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 3982. * CV.LB_TO_KG + STD_CARGO_KG
ret.wheelbase = 2.766 ret.wheelbase = 2.766
# Values from optimizer # Values from optimizer
ret.steerRatio = 16.55 # 13.8 is spec end-to-end ret.steerRatio = 16.55 # 13.8 is spec end-to-end
tire_stiffness_factor = 0.82 tire_stiffness_factor = 0.82
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[9., 22.], [9., 22.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2, 0.35], [0.05, 0.09]]
elif candidate in (CAR.SONATA, CAR.SONATA_HYBRID): elif candidate in (CAR.SONATA, CAR.SONATA_HYBRID):
ret.mass = 1513. + STD_CARGO_KG ret.mass = 1513. + STD_CARGO_KG
ret.wheelbase = 2.84 ret.wheelbase = 2.84
ret.steerRatio = 13.27 * 1.15 # 15% higher at the center seems reasonable ret.steerRatio = 13.27 * 1.15 # 15% higher at the center seems reasonable
tire_stiffness_factor = 0.65 tire_stiffness_factor = 0.65
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.SONATA_LF: elif candidate == CAR.SONATA_LF:
ret.lateralTuning.pid.kf = 0.00005
ret.mass = 4497. * CV.LB_TO_KG ret.mass = 4497. * CV.LB_TO_KG
ret.wheelbase = 2.804 ret.wheelbase = 2.804
ret.steerRatio = 13.27 * 1.15 # 15% higher at the center seems reasonable ret.steerRatio = 13.27 * 1.15 # 15% higher at the center seems reasonable
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]]
elif candidate == CAR.PALISADE: elif candidate == CAR.PALISADE:
ret.lateralTuning.pid.kf = 0.00005
ret.mass = 1999. + STD_CARGO_KG ret.mass = 1999. + STD_CARGO_KG
ret.wheelbase = 2.90 ret.wheelbase = 2.90
ret.steerRatio = 15.6 * 1.15 ret.steerRatio = 15.6 * 1.15
tire_stiffness_factor = 0.63 tire_stiffness_factor = 0.63
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) elif candidate == CAR.ELANTRA:
elif candidate in (CAR.ELANTRA, CAR.ELANTRA_GT_I30):
ret.lateralTuning.pid.kf = 0.00006
ret.mass = 1275. + STD_CARGO_KG ret.mass = 1275. + STD_CARGO_KG
ret.wheelbase = 2.7 ret.wheelbase = 2.7
ret.steerRatio = 15.4 # 14 is Stock | Settled Params Learner values are steerRatio: 15.401566348670535 ret.steerRatio = 15.4 # 14 is Stock | Settled Params Learner values are steerRatio: 15.401566348670535
tire_stiffness_factor = 0.385 # stiffnessFactor settled on 1.0081302973865127 tire_stiffness_factor = 0.385 # stiffnessFactor settled on 1.0081302973865127
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]]
ret.minSteerSpeed = 32 * CV.MPH_TO_MS ret.minSteerSpeed = 32 * CV.MPH_TO_MS
elif candidate == CAR.ELANTRA_2021: elif candidate == CAR.ELANTRA_2021:
ret.mass = (2800. * CV.LB_TO_KG) + STD_CARGO_KG ret.mass = (2800. * CV.LB_TO_KG) + STD_CARGO_KG
ret.wheelbase = 2.72 ret.wheelbase = 2.72
ret.steerRatio = 12.9 ret.steerRatio = 12.9
tire_stiffness_factor = 0.65 tire_stiffness_factor = 0.65
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.ELANTRA_HEV_2021: elif candidate == CAR.ELANTRA_HEV_2021:
ret.mass = (3017. * CV.LB_TO_KG) + STD_CARGO_KG ret.mass = (3017. * CV.LB_TO_KG) + STD_CARGO_KG
ret.wheelbase = 2.72 ret.wheelbase = 2.72
ret.steerRatio = 12.9 ret.steerRatio = 12.9
tire_stiffness_factor = 0.65 tire_stiffness_factor = 0.65
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.HYUNDAI_GENESIS: elif candidate == CAR.HYUNDAI_GENESIS:
ret.lateralTuning.pid.kf = 0.00005
ret.mass = 2060. + STD_CARGO_KG ret.mass = 2060. + STD_CARGO_KG
ret.wheelbase = 3.01 ret.wheelbase = 3.01
ret.steerRatio = 16.5 ret.steerRatio = 16.5
ret.lateralTuning.init('indi')
ret.lateralTuning.indi.innerLoopGainBP = [0.]
ret.lateralTuning.indi.innerLoopGainV = [3.5]
ret.lateralTuning.indi.outerLoopGainBP = [0.]
ret.lateralTuning.indi.outerLoopGainV = [2.0]
ret.lateralTuning.indi.timeConstantBP = [0.]
ret.lateralTuning.indi.timeConstantV = [1.4]
ret.lateralTuning.indi.actuatorEffectivenessBP = [0.]
ret.lateralTuning.indi.actuatorEffectivenessV = [2.3]
ret.minSteerSpeed = 60 * CV.KPH_TO_MS ret.minSteerSpeed = 60 * CV.KPH_TO_MS
elif candidate in (CAR.KONA, CAR.KONA_EV, CAR.KONA_HEV, CAR.KONA_EV_2022): elif candidate in (CAR.KONA, CAR.KONA_EV, CAR.KONA_HEV, CAR.KONA_EV_2022):
ret.mass = {CAR.KONA_EV: 1685., CAR.KONA_HEV: 1425., CAR.KONA_EV_2022: 1743.}.get(candidate, 1275.) + STD_CARGO_KG ret.mass = {CAR.KONA_EV: 1685., CAR.KONA_HEV: 1425., CAR.KONA_EV_2022: 1743.}.get(candidate, 1275.) + STD_CARGO_KG
ret.wheelbase = 2.6 ret.wheelbase = 2.6
ret.steerRatio = 13.42 # Spec ret.steerRatio = 13.42 # Spec
tire_stiffness_factor = 0.385 tire_stiffness_factor = 0.385
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate in (CAR.IONIQ, CAR.IONIQ_EV_LTD, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.IONIQ_HEV_2022): elif candidate in (CAR.IONIQ, CAR.IONIQ_EV_LTD, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.IONIQ_HEV_2022):
ret.lateralTuning.pid.kf = 0.00006
ret.mass = 1490. + STD_CARGO_KG # weight per hyundai site https://www.hyundaiusa.com/ioniq-electric/specifications.aspx ret.mass = 1490. + STD_CARGO_KG # weight per hyundai site https://www.hyundaiusa.com/ioniq-electric/specifications.aspx
ret.wheelbase = 2.7 ret.wheelbase = 2.7
ret.steerRatio = 13.73 # Spec ret.steerRatio = 13.73 # Spec
tire_stiffness_factor = 0.385 tire_stiffness_factor = 0.385
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]]
if candidate not in (CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.IONIQ_HEV_2022): if candidate not in (CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.IONIQ_HEV_2022):
ret.minSteerSpeed = 32 * CV.MPH_TO_MS ret.minSteerSpeed = 32 * CV.MPH_TO_MS
elif candidate == CAR.IONIQ_PHEV_2019: elif candidate == CAR.IONIQ_PHEV_2019:
ret.mass = 1550. + STD_CARGO_KG # weight per hyundai site https://www.hyundaiusa.com/us/en/vehicles/2019-ioniq-plug-in-hybrid/compare-specs ret.mass = 1550. + STD_CARGO_KG # weight per hyundai site https://www.hyundaiusa.com/us/en/vehicles/2019-ioniq-plug-in-hybrid/compare-specs
ret.wheelbase = 2.7 ret.wheelbase = 2.7
ret.steerRatio = 13.73 ret.steerRatio = 13.73
ret.lateralTuning.init('indi')
ret.lateralTuning.indi.innerLoopGainBP = [0.]
ret.lateralTuning.indi.innerLoopGainV = [2.5]
ret.lateralTuning.indi.outerLoopGainBP = [0.]
ret.lateralTuning.indi.outerLoopGainV = [3.5]
ret.lateralTuning.indi.timeConstantBP = [0.]
ret.lateralTuning.indi.timeConstantV = [1.4]
ret.lateralTuning.indi.actuatorEffectivenessBP = [0.]
ret.lateralTuning.indi.actuatorEffectivenessV = [1.8]
ret.minSteerSpeed = 32 * CV.MPH_TO_MS ret.minSteerSpeed = 32 * CV.MPH_TO_MS
elif candidate == CAR.VELOSTER: elif candidate == CAR.VELOSTER:
ret.lateralTuning.pid.kf = 0.00005
ret.mass = 3558. * CV.LB_TO_KG ret.mass = 3558. * CV.LB_TO_KG
ret.wheelbase = 2.80 ret.wheelbase = 2.80
ret.steerRatio = 13.75 * 1.15 ret.steerRatio = 13.75 * 1.15
tire_stiffness_factor = 0.5 tire_stiffness_factor = 0.5
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]]
elif candidate == CAR.TUCSON: elif candidate == CAR.TUCSON:
ret.lateralTuning.pid.kf = 0.00005
ret.mass = 3520. * CV.LB_TO_KG ret.mass = 3520. * CV.LB_TO_KG
ret.wheelbase = 2.67 ret.wheelbase = 2.67
ret.steerRatio = 14.00 * 1.15 ret.steerRatio = 14.00 * 1.15
tire_stiffness_factor = 0.385 tire_stiffness_factor = 0.385
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]]
elif candidate == CAR.TUCSON_HYBRID_4TH_GEN: elif candidate == CAR.TUCSON_HYBRID_4TH_GEN:
ret.mass = 1680. + STD_CARGO_KG # average of all 3 trims ret.mass = 1680. + STD_CARGO_KG # average of all 3 trims
ret.wheelbase = 2.756 ret.wheelbase = 2.756
ret.steerRatio = 16. ret.steerRatio = 16.
tire_stiffness_factor = 0.385 tire_stiffness_factor = 0.385
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
# Kia # Kia
elif candidate == CAR.KIA_SORENTO: elif candidate == CAR.KIA_SORENTO:
ret.lateralTuning.pid.kf = 0.00005
ret.mass = 1985. + STD_CARGO_KG ret.mass = 1985. + STD_CARGO_KG
ret.wheelbase = 2.78 ret.wheelbase = 2.78
ret.steerRatio = 14.4 * 1.1 # 10% higher at the center seems reasonable ret.steerRatio = 14.4 * 1.1 # 10% higher at the center seems reasonable
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]]
elif candidate in (CAR.KIA_NIRO_EV, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021): elif candidate in (CAR.KIA_NIRO_EV, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021):
ret.lateralTuning.pid.kf = 0.00006
ret.mass = 1737. + STD_CARGO_KG ret.mass = 1737. + STD_CARGO_KG
ret.wheelbase = 2.7 ret.wheelbase = 2.7
ret.steerRatio = 13.9 if CAR.KIA_NIRO_HEV_2021 else 13.73 # Spec ret.steerRatio = 13.9 if CAR.KIA_NIRO_HEV_2021 else 13.73 # Spec
tire_stiffness_factor = 0.385 tire_stiffness_factor = 0.385
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]]
if candidate == CAR.KIA_NIRO_PHEV: if candidate == CAR.KIA_NIRO_PHEV:
ret.minSteerSpeed = 32 * CV.MPH_TO_MS ret.minSteerSpeed = 32 * CV.MPH_TO_MS
elif candidate == CAR.KIA_SELTOS: elif candidate == CAR.KIA_SELTOS:
@ -186,15 +138,6 @@ class CarInterface(CarInterfaceBase):
ret.wheelbase = 2.63 ret.wheelbase = 2.63
ret.steerRatio = 14.56 ret.steerRatio = 14.56
tire_stiffness_factor = 1 tire_stiffness_factor = 1
ret.lateralTuning.init('indi')
ret.lateralTuning.indi.innerLoopGainBP = [0.]
ret.lateralTuning.indi.innerLoopGainV = [4.]
ret.lateralTuning.indi.outerLoopGainBP = [0.]
ret.lateralTuning.indi.outerLoopGainV = [3.]
ret.lateralTuning.indi.timeConstantBP = [0.]
ret.lateralTuning.indi.timeConstantV = [1.4]
ret.lateralTuning.indi.actuatorEffectivenessBP = [0.]
ret.lateralTuning.indi.actuatorEffectivenessV = [1.8]
elif candidate in (CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL, CAR.KIA_OPTIMA_H): elif candidate in (CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL, CAR.KIA_OPTIMA_H):
ret.mass = 3558. * CV.LB_TO_KG ret.mass = 3558. * CV.LB_TO_KG
ret.wheelbase = 2.80 ret.wheelbase = 2.80
@ -202,87 +145,58 @@ class CarInterface(CarInterfaceBase):
tire_stiffness_factor = 0.5 tire_stiffness_factor = 0.5
if candidate == CAR.KIA_OPTIMA_G4: if candidate == CAR.KIA_OPTIMA_G4:
ret.minSteerSpeed = 32 * CV.MPH_TO_MS ret.minSteerSpeed = 32 * CV.MPH_TO_MS
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.KIA_STINGER: elif candidate == CAR.KIA_STINGER:
ret.lateralTuning.pid.kf = 0.00005
ret.mass = 1825. + STD_CARGO_KG ret.mass = 1825. + STD_CARGO_KG
ret.wheelbase = 2.78 ret.wheelbase = 2.78
ret.steerRatio = 14.4 * 1.15 # 15% higher at the center seems reasonable ret.steerRatio = 14.4 * 1.15 # 15% higher at the center seems reasonable
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]]
elif candidate == CAR.KIA_FORTE: elif candidate == CAR.KIA_FORTE:
ret.lateralTuning.pid.kf = 0.00005
ret.mass = 3558. * CV.LB_TO_KG ret.mass = 3558. * CV.LB_TO_KG
ret.wheelbase = 2.80 ret.wheelbase = 2.80
ret.steerRatio = 13.75 ret.steerRatio = 13.75
tire_stiffness_factor = 0.5 tire_stiffness_factor = 0.5
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]]
elif candidate == CAR.KIA_CEED: elif candidate == CAR.KIA_CEED:
ret.lateralTuning.pid.kf = 0.00005
ret.mass = 1450. + STD_CARGO_KG ret.mass = 1450. + STD_CARGO_KG
ret.wheelbase = 2.65 ret.wheelbase = 2.65
ret.steerRatio = 13.75 ret.steerRatio = 13.75
tire_stiffness_factor = 0.5 tire_stiffness_factor = 0.5
ret.lateralTuning.pid.kf = 0.00005
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]]
elif candidate == CAR.KIA_K5_2021: elif candidate == CAR.KIA_K5_2021:
ret.lateralTuning.pid.kf = 0.00005
ret.mass = 3228. * CV.LB_TO_KG ret.mass = 3228. * CV.LB_TO_KG
ret.wheelbase = 2.85 ret.wheelbase = 2.85
ret.steerRatio = 13.27 # 2021 Kia K5 Steering Ratio (all trims) ret.steerRatio = 13.27 # 2021 Kia K5 Steering Ratio (all trims)
tire_stiffness_factor = 0.5 tire_stiffness_factor = 0.5
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]]
elif candidate == CAR.KIA_EV6: elif candidate == CAR.KIA_EV6:
ret.mass = 2055 + STD_CARGO_KG ret.mass = 2055 + STD_CARGO_KG
ret.wheelbase = 2.9 ret.wheelbase = 2.9
ret.steerRatio = 16. ret.steerRatio = 16.
tire_stiffness_factor = 0.65 tire_stiffness_factor = 0.65
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.IONIQ_5: elif candidate == CAR.IONIQ_5:
ret.mass = 2012 + STD_CARGO_KG ret.mass = 2012 + STD_CARGO_KG
ret.wheelbase = 3.0 ret.wheelbase = 3.0
ret.steerRatio = 16. ret.steerRatio = 16.
tire_stiffness_factor = 0.65 tire_stiffness_factor = 0.65
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) elif candidate == CAR.KIA_SPORTAGE_HYBRID_5TH_GEN:
ret.mass = 1767. + STD_CARGO_KG # SX Prestige trim support only
ret.wheelbase = 2.756
ret.steerRatio = 13.6
# Genesis # Genesis
elif candidate == CAR.GENESIS_G70: elif candidate == CAR.GENESIS_G70:
ret.lateralTuning.init('indi')
ret.lateralTuning.indi.innerLoopGainBP = [0.]
ret.lateralTuning.indi.innerLoopGainV = [2.5]
ret.lateralTuning.indi.outerLoopGainBP = [0.]
ret.lateralTuning.indi.outerLoopGainV = [3.5]
ret.lateralTuning.indi.timeConstantBP = [0.]
ret.lateralTuning.indi.timeConstantV = [1.4]
ret.lateralTuning.indi.actuatorEffectivenessBP = [0.]
ret.lateralTuning.indi.actuatorEffectivenessV = [1.8]
ret.steerActuatorDelay = 0.1 ret.steerActuatorDelay = 0.1
ret.mass = 1640.0 + STD_CARGO_KG ret.mass = 1640.0 + STD_CARGO_KG
ret.wheelbase = 2.84 ret.wheelbase = 2.84
ret.steerRatio = 13.56 ret.steerRatio = 13.56
elif candidate == CAR.GENESIS_G70_2020: elif candidate == CAR.GENESIS_G70_2020:
ret.lateralTuning.pid.kf = 0.
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.112], [0.004]]
ret.mass = 3673.0 * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 3673.0 * CV.LB_TO_KG + STD_CARGO_KG
ret.wheelbase = 2.83 ret.wheelbase = 2.83
ret.steerRatio = 12.9 ret.steerRatio = 12.9
elif candidate == CAR.GENESIS_G80: elif candidate == CAR.GENESIS_G80:
ret.lateralTuning.pid.kf = 0.00005
ret.mass = 2060. + STD_CARGO_KG ret.mass = 2060. + STD_CARGO_KG
ret.wheelbase = 3.01 ret.wheelbase = 3.01
ret.steerRatio = 16.5 ret.steerRatio = 16.5
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.16], [0.01]]
elif candidate == CAR.GENESIS_G90: elif candidate == CAR.GENESIS_G90:
ret.mass = 2200 ret.mass = 2200
ret.wheelbase = 3.15 ret.wheelbase = 3.15
ret.steerRatio = 12.069 ret.steerRatio = 12.069
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.16], [0.01]]
# *** longitudinal control *** # *** longitudinal control ***
if candidate in CANFD_CAR: if candidate in CANFD_CAR:
@ -305,6 +219,13 @@ class CarInterface(CarInterfaceBase):
ret.vEgoStarting = 0.1 ret.vEgoStarting = 0.1
ret.startAccel = 2.0 ret.startAccel = 2.0
# *** feature detection ***
if candidate in CANFD_CAR:
bus = 5 if ret.flags & HyundaiFlags.CANFD_HDA2 else 4
ret.enableBsm = 0x1e5 in fingerprint[bus]
else:
ret.enableBsm = 0x58b in fingerprint[0]
# *** panda safety config *** # *** panda safety config ***
if candidate in CANFD_CAR: if candidate in CANFD_CAR:
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.noOutput), ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.noOutput),
@ -315,8 +236,6 @@ class CarInterface(CarInterfaceBase):
if ret.flags & HyundaiFlags.CANFD_ALT_BUTTONS: if ret.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
ret.safetyConfigs[1].safetyParam |= Panda.FLAG_HYUNDAI_CANFD_ALT_BUTTONS ret.safetyConfigs[1].safetyParam |= Panda.FLAG_HYUNDAI_CANFD_ALT_BUTTONS
else: else:
ret.enableBsm = 0x58b in fingerprint[0]
if candidate in LEGACY_SAFETY_MODE_CAR: if candidate in LEGACY_SAFETY_MODE_CAR:
# these cars require a special panda safety mode due to missing counters and checksums in the messages # these cars require a special panda safety mode due to missing counters and checksums in the messages
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.hyundaiLegacy)] ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.hyundaiLegacy)]

@ -0,0 +1,29 @@
#!/usr/bin/env python3
import unittest
from cereal import car
from selfdrive.car.car_helpers import get_interface_attr
from selfdrive.car.fw_versions import FW_QUERY_CONFIGS
from selfdrive.car.hyundai.values import CANFD_CAR
Ecu = car.CarParams.Ecu
ECU_NAME = {v: k for k, v in Ecu.schema.enumerants.items()}
VERSIONS = get_interface_attr("FW_VERSIONS", ignore_none=True)
class TestHyundaiFingerprint(unittest.TestCase):
def test_auxiliary_request_ecu_whitelist(self):
# Asserts only auxiliary Ecus can exist in database for CAN-FD cars
config = FW_QUERY_CONFIGS['hyundai']
whitelisted_ecus = {ecu for r in config.requests for ecu in r.whitelist_ecus if r.bus > 3}
for car_model in CANFD_CAR:
ecus = {fw[0] for fw in VERSIONS['hyundai'][car_model].keys()}
ecus_not_in_whitelist = ecus - whitelisted_ecus
ecu_strings = ", ".join([f'Ecu.{ECU_NAME[ecu]}' for ecu in ecus_not_in_whitelist])
self.assertEqual(len(ecus_not_in_whitelist), 0, f'{car_model}: Car model has ECUs not in auxiliary request whitelists: {ecu_strings}')
if __name__ == "__main__":
unittest.main()

@ -34,9 +34,9 @@ class CarControllerParams:
# To determine the limit for your car, find the maximum value that the stock LKAS will request. # To determine the limit for your car, find the maximum value that the stock LKAS will request.
# If the max stock LKAS request is <384, add your car to this list. # If the max stock LKAS request is <384, add your car to this list.
elif CP.carFingerprint in (CAR.GENESIS_G80, CAR.GENESIS_G90, CAR.ELANTRA, CAR.HYUNDAI_GENESIS, CAR.ELANTRA_GT_I30, CAR.IONIQ, elif CP.carFingerprint in (CAR.GENESIS_G80, CAR.GENESIS_G90, CAR.ELANTRA, CAR.HYUNDAI_GENESIS, CAR.IONIQ,
CAR.IONIQ_EV_LTD, CAR.SANTA_FE_PHEV_2022, CAR.SONATA_LF, CAR.KIA_FORTE, CAR.KIA_NIRO_PHEV, CAR.IONIQ_EV_LTD, CAR.SANTA_FE_PHEV_2022, CAR.SONATA_LF, CAR.KIA_FORTE, CAR.KIA_NIRO_PHEV,
CAR.KIA_OPTIMA_H, CAR.KIA_SORENTO, CAR.KIA_STINGER): CAR.KIA_OPTIMA_H, CAR.KIA_SORENTO):
self.STEER_MAX = 255 self.STEER_MAX = 255
# Default for most HKG # Default for most HKG
@ -54,7 +54,6 @@ class CAR:
ELANTRA = "HYUNDAI ELANTRA 2017" ELANTRA = "HYUNDAI ELANTRA 2017"
ELANTRA_2021 = "HYUNDAI ELANTRA 2021" ELANTRA_2021 = "HYUNDAI ELANTRA 2021"
ELANTRA_HEV_2021 = "HYUNDAI ELANTRA HYBRID 2021" ELANTRA_HEV_2021 = "HYUNDAI ELANTRA HYBRID 2021"
ELANTRA_GT_I30 = "HYUNDAI I30 N LINE 2019 & GT 2018 DCT"
HYUNDAI_GENESIS = "HYUNDAI GENESIS 2015-2016" HYUNDAI_GENESIS = "HYUNDAI GENESIS 2015-2016"
IONIQ = "HYUNDAI IONIQ HYBRID 2017-2019" IONIQ = "HYUNDAI IONIQ HYBRID 2017-2019"
IONIQ_HEV_2022 = "HYUNDAI IONIQ HYBRID 2020-2022" IONIQ_HEV_2022 = "HYUNDAI IONIQ HYBRID 2020-2022"
@ -90,6 +89,7 @@ class CAR:
KIA_OPTIMA_H = "KIA OPTIMA HYBRID 2017 & SPORTS 2019" KIA_OPTIMA_H = "KIA OPTIMA HYBRID 2017 & SPORTS 2019"
KIA_SELTOS = "KIA SELTOS 2021" KIA_SELTOS = "KIA SELTOS 2021"
KIA_SORENTO = "KIA SORENTO GT LINE 2018" KIA_SORENTO = "KIA SORENTO GT LINE 2018"
KIA_SPORTAGE_HYBRID_5TH_GEN = "KIA SPORTAGE HYBRID 5TH GEN"
KIA_STINGER = "KIA STINGER GT2 2018" KIA_STINGER = "KIA STINGER GT2 2018"
KIA_CEED = "KIA CEED INTRO ED 2019" KIA_CEED = "KIA CEED INTRO ED 2019"
KIA_EV6 = "KIA EV6 2022" KIA_EV6 = "KIA EV6 2022"
@ -107,13 +107,13 @@ class HyundaiCarInfo(CarInfo):
CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = {
CAR.ELANTRA: HyundaiCarInfo("Hyundai Elantra 2017-19", min_enable_speed=19 * CV.MPH_TO_MS, harness=Harness.hyundai_b), CAR.ELANTRA: [
CAR.ELANTRA_2021: HyundaiCarInfo("Hyundai Elantra 2021-22", video_link="https://youtu.be/_EdYQtV52-c", harness=Harness.hyundai_k), HyundaiCarInfo("Hyundai Elantra 2017-19", min_enable_speed=19 * CV.MPH_TO_MS, harness=Harness.hyundai_b),
CAR.ELANTRA_HEV_2021: HyundaiCarInfo("Hyundai Elantra Hybrid 2021-23", video_link="https://youtu.be/_EdYQtV52-c", harness=Harness.hyundai_k),
CAR.ELANTRA_GT_I30: [
HyundaiCarInfo("Hyundai Elantra GT 2017-19", harness=Harness.hyundai_e), HyundaiCarInfo("Hyundai Elantra GT 2017-19", harness=Harness.hyundai_e),
HyundaiCarInfo("Hyundai i30 2019", harness=Harness.hyundai_e), HyundaiCarInfo("Hyundai i30 2019", harness=Harness.hyundai_e),
], ],
CAR.ELANTRA_2021: HyundaiCarInfo("Hyundai Elantra 2021-22", video_link="https://youtu.be/_EdYQtV52-c", harness=Harness.hyundai_k),
CAR.ELANTRA_HEV_2021: HyundaiCarInfo("Hyundai Elantra Hybrid 2021-23", video_link="https://youtu.be/_EdYQtV52-c", harness=Harness.hyundai_k),
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", 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
@ -172,6 +172,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = {
HyundaiCarInfo("Kia Sorento 2018", "Advanced Smart Cruise Control", "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_SPORTAGE_HYBRID_5TH_GEN: HyundaiCarInfo("Kia Sportage Hybrid 2023", harness=Harness.hyundai_n),
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),
CAR.KIA_CEED: HyundaiCarInfo("Kia Ceed 2019", harness=Harness.hyundai_e), CAR.KIA_CEED: HyundaiCarInfo("Kia Ceed 2019", harness=Harness.hyundai_e),
CAR.KIA_EV6: [ CAR.KIA_EV6: [
@ -197,15 +198,6 @@ FINGERPRINTS = {
CAR.ELANTRA: [{ CAR.ELANTRA: [{
66: 8, 67: 8, 68: 8, 127: 8, 273: 8, 274: 8, 275: 8, 339: 8, 356: 4, 399: 8, 512: 6, 544: 8, 593: 8, 608: 8, 688: 5, 790: 8, 809: 8, 897: 8, 832: 8, 899: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1170: 8, 1265: 4, 1280: 1, 1282: 4, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1314: 8, 1322: 8, 1345: 8, 1349: 8, 1351: 8, 1353: 8, 1363: 8, 1366: 8, 1367: 8, 1369: 8, 1407: 8, 1415: 8, 1419: 8, 1425: 2, 1427: 6, 1440: 8, 1456: 4, 1472: 8, 1486: 8, 1487: 8, 1491: 8, 1530: 8, 1532: 5, 2001: 8, 2003: 8, 2004: 8, 2009: 8, 2012: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8 66: 8, 67: 8, 68: 8, 127: 8, 273: 8, 274: 8, 275: 8, 339: 8, 356: 4, 399: 8, 512: 6, 544: 8, 593: 8, 608: 8, 688: 5, 790: 8, 809: 8, 897: 8, 832: 8, 899: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1170: 8, 1265: 4, 1280: 1, 1282: 4, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1314: 8, 1322: 8, 1345: 8, 1349: 8, 1351: 8, 1353: 8, 1363: 8, 1366: 8, 1367: 8, 1369: 8, 1407: 8, 1415: 8, 1419: 8, 1425: 2, 1427: 6, 1440: 8, 1456: 4, 1472: 8, 1486: 8, 1487: 8, 1491: 8, 1530: 8, 1532: 5, 2001: 8, 2003: 8, 2004: 8, 2009: 8, 2012: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8
}], }],
CAR.ELANTRA_GT_I30: [{
66: 8, 67: 8, 68: 8, 127: 8, 128: 8, 129: 8, 273: 8, 274: 8, 275: 8, 339: 8, 354: 3, 356: 4, 399: 8, 512: 6, 544: 8, 593: 8, 608: 8, 688: 5, 790: 8, 809: 8, 884: 8, 897: 8, 899: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1151: 6, 1168: 7, 1170: 8, 1193: 8, 1265: 4, 1280: 1, 1282: 4, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1345: 8, 1348: 8, 1349: 8, 1351: 8, 1353: 8, 1356: 8, 1363: 8, 1365: 8, 1366: 8, 1367: 8, 1369: 8, 1407: 8, 1414: 3, 1415: 8, 1427: 6, 1440: 8, 1456: 4, 1470: 8, 1486: 8, 1487: 8, 1491: 8, 1530: 8, 1952: 8, 1960: 8, 1988: 8, 2000: 8, 2001: 8, 2005: 8, 2008: 8, 2009: 8, 2013: 8, 2017: 8, 2025: 8
},
{
66: 8, 67: 8, 68: 8, 127: 8, 128: 8, 129: 8, 273: 8, 274: 8, 275: 8, 339: 8, 354: 3, 356: 4, 399: 8, 512: 6, 544: 8, 593: 8, 608: 8, 688: 5, 790: 8, 809: 8, 832: 8, 897: 8, 899: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1151: 6, 1168: 7, 1170: 8, 1265: 4, 1280: 1, 1282: 4, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1349: 8, 1351: 8, 1353: 8, 1356: 8, 1363: 8, 1366: 8, 1367: 8, 1369: 8, 1407: 8, 1414: 3, 1415: 8, 1419: 8, 1440: 8, 1456: 4, 1470: 8, 1486: 8, 1487: 8, 1491: 8, 1530: 8
},
{
66: 8, 67: 8, 68: 8, 127: 8, 128: 8, 129: 8, 273: 8, 274: 8, 275: 8, 339: 8, 354: 3, 356: 4, 399: 8, 512: 6, 544: 8, 593: 8, 608: 8, 688: 5, 790: 8, 809: 8, 832: 8, 897: 8, 899: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1151: 6, 1168: 7, 1170: 8, 1265: 4, 1280: 1, 1282: 4, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1349: 8, 1351: 8, 1353: 8, 1356: 8, 1363: 8, 1366: 8, 1367: 8, 1369: 8, 1407: 8, 1414: 3, 1419: 8, 1427: 6, 1440: 8, 1456: 4, 1470: 8, 1486: 8, 1487: 8, 1491: 8, 1960: 8, 1990: 8, 1998: 8, 2000: 8, 2001: 8, 2004: 8, 2005: 8, 2008: 8, 2009: 8, 2012: 8, 2013: 8, 2015: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8
}],
CAR.HYUNDAI_GENESIS: [{ CAR.HYUNDAI_GENESIS: [{
67: 8, 68: 8, 304: 8, 320: 8, 339: 8, 356: 4, 544: 7, 593: 8, 608: 8, 688: 5, 809: 8, 832: 8, 854: 7, 870: 7, 871: 8, 872: 5, 897: 8, 902: 8, 903: 6, 916: 8, 1024: 2, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1168: 7, 1170: 8, 1173: 8, 1184: 8, 1265: 4, 1280: 1, 1287: 4, 1292: 8, 1312: 8, 1322: 8, 1331: 8, 1332: 8, 1333: 8, 1334: 8, 1335: 8, 1342: 6, 1345: 8, 1363: 8, 1369: 8, 1370: 8, 1371: 8, 1378: 4, 1384: 5, 1407: 8, 1419: 8, 1427: 6, 1434: 2, 1456: 4 67: 8, 68: 8, 304: 8, 320: 8, 339: 8, 356: 4, 544: 7, 593: 8, 608: 8, 688: 5, 809: 8, 832: 8, 854: 7, 870: 7, 871: 8, 872: 5, 897: 8, 902: 8, 903: 6, 916: 8, 1024: 2, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1168: 7, 1170: 8, 1173: 8, 1184: 8, 1265: 4, 1280: 1, 1287: 4, 1292: 8, 1312: 8, 1322: 8, 1331: 8, 1332: 8, 1333: 8, 1334: 8, 1335: 8, 1342: 6, 1345: 8, 1363: 8, 1369: 8, 1370: 8, 1371: 8, 1378: 4, 1384: 5, 1407: 8, 1419: 8, 1427: 6, 1434: 2, 1456: 4
}, },
@ -290,17 +282,35 @@ HYUNDAI_VERSION_RESPONSE = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER + 0x4
FW_QUERY_CONFIG = FwQueryConfig( FW_QUERY_CONFIG = FwQueryConfig(
requests=[ requests=[
# TODO: minimize shared whitelists for CAN and cornerRadar for CAN-FD
# CAN queries (OBD-II port)
Request( Request(
[HYUNDAI_VERSION_REQUEST_LONG], [HYUNDAI_VERSION_REQUEST_LONG],
[HYUNDAI_VERSION_RESPONSE], [HYUNDAI_VERSION_RESPONSE],
whitelist_ecus=[Ecu.transmission, Ecu.eps, Ecu.abs, Ecu.fwdRadar, Ecu.fwdCamera],
), ),
Request( Request(
[HYUNDAI_VERSION_REQUEST_MULTI], [HYUNDAI_VERSION_REQUEST_MULTI],
[HYUNDAI_VERSION_RESPONSE], [HYUNDAI_VERSION_RESPONSE],
whitelist_ecus=[Ecu.engine, Ecu.transmission, Ecu.eps, Ecu.abs, Ecu.fwdRadar],
),
# CAN-FD queries (camera)
Request(
[HYUNDAI_VERSION_REQUEST_LONG],
[HYUNDAI_VERSION_RESPONSE],
whitelist_ecus=[Ecu.fwdCamera, Ecu.fwdRadar, Ecu.cornerRadar],
bus=4,
),
Request(
[HYUNDAI_VERSION_REQUEST_LONG],
[HYUNDAI_VERSION_RESPONSE],
whitelist_ecus=[Ecu.fwdCamera, Ecu.adas, Ecu.cornerRadar],
bus=5,
), ),
], ],
extra_ecus=[ extra_ecus=[
(Ecu.adas, 0x730, None), # ADAS Driving ECU on HDA2 platforms (Ecu.adas, 0x730, None), # ADAS Driving ECU on HDA2 platforms
(Ecu.cornerRadar, 0x7b7, None),
], ],
) )
@ -741,6 +751,7 @@ FW_VERSIONS = {
b'\xf1\x81640E0051\x00\x00\x00\x00\x00\x00\x00\x00', b'\xf1\x81640E0051\x00\x00\x00\x00\x00\x00\x00\x00',
b'\xf1\x82CKJN3TMSDE0B\x00\x00\x00\x00', b'\xf1\x82CKJN3TMSDE0B\x00\x00\x00\x00',
b'\xf1\x82CKKN3TMD_H0A\x00\x00\x00\x00', b'\xf1\x82CKKN3TMD_H0A\x00\x00\x00\x00',
b'\xe0\x19\xff\xe7\xe7g\x01\xa2\x00\x0f\x00\x9e\x00\x06\x00\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\x00\x00\x0f\x0e\x0f\x0f\x0e\r\x00\x00\x7f\x02.\xff\x00\x00~p\x00\x00\x00\x00u\xff\xf9\xff\x00\x00\x00\x00V\t\xd5\x01\xc0\x00\x00\x00\x007\xfb\xfc\x0b\x8d\x00',
], ],
(Ecu.eps, 0x7d4, None): [ (Ecu.eps, 0x7d4, None): [
b'\xf1\x00CK MDPS R 1.00 1.04 57700-J5200 4C2CL104', b'\xf1\x00CK MDPS R 1.00 1.04 57700-J5200 4C2CL104',
@ -763,10 +774,14 @@ FW_VERSIONS = {
b'\xf1\x87VDKLJ18675252DK6\x89vhgwwwwveVU\x88w\x87w\x99vgf\x97vXfgw_\xff\xc2\xfb\xf1\x89E25\x00\x00\x00\x00\x00\x00\x00\xf1\x82TCK0T33NB2', b'\xf1\x87VDKLJ18675252DK6\x89vhgwwwwveVU\x88w\x87w\x99vgf\x97vXfgw_\xff\xc2\xfb\xf1\x89E25\x00\x00\x00\x00\x00\x00\x00\xf1\x82TCK0T33NB2',
b'\xf1\x87WAJTE17552812CH4vfFffvfVeT5DwvvVVdFeegeg\x88\x88o\xff\x1a]\xf1\x81E21\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00TCK2T20NB1\x19\xd2\x00\x94', b'\xf1\x87WAJTE17552812CH4vfFffvfVeT5DwvvVVdFeegeg\x88\x88o\xff\x1a]\xf1\x81E21\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00TCK2T20NB1\x19\xd2\x00\x94',
b'\xf1\x87VDHLG17274082DK2wfFf\x89x\x98wUT5T\x88v\x97xgeGefTGTVvO\xff\x1c\x14\xf1\x81E19\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E19\x00\x00\x00\x00\x00\x00\x00SCK0T33UB2\xee[\x97S', b'\xf1\x87VDHLG17274082DK2wfFf\x89x\x98wUT5T\x88v\x97xgeGefTGTVvO\xff\x1c\x14\xf1\x81E19\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E19\x00\x00\x00\x00\x00\x00\x00SCK0T33UB2\xee[\x97S',
b'\xf1\x87VDHLG17000192DK2xdFffT\xa5VUD$DwT\x86wveVeeD&T\x99\xba\x8f\xff\xcc\x99\xf1\x81E21\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SCK0T33NB0\t\xb7\x17\xf5',
b'\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SCK0T33NB0\t\xb7\x17\xf5',
b'\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SCK0T33NB0\x88\xa2\xe6\xf0',
], ],
}, },
CAR.PALISADE: { CAR.PALISADE: {
(Ecu.fwdRadar, 0x7d0, None): [ (Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00LX2_ SCC F-CUP 1.00 1.04 99110-S8100 ',
b'\xf1\x00LX2_ SCC F-CUP 1.00 1.05 99110-S8100 ', b'\xf1\x00LX2_ SCC F-CUP 1.00 1.05 99110-S8100 ',
b'\xf1\x00LX2 SCC FHCUP 1.00 1.04 99110-S8100 ', b'\xf1\x00LX2 SCC FHCUP 1.00 1.04 99110-S8100 ',
b'\xf1\x00LX2_ SCC FHCU- 1.00 1.05 99110-S8100 ', b'\xf1\x00LX2_ SCC FHCU- 1.00 1.05 99110-S8100 ',
@ -780,6 +795,7 @@ FW_VERSIONS = {
b'\xf1\x00LX ESC \x01 1031\t\x10 58910-S8360', b'\xf1\x00LX ESC \x01 1031\t\x10 58910-S8360',
b'\xf1\x00LX ESC \x0b 101\x19\x03\x17 58910-S8330', b'\xf1\x00LX ESC \x0b 101\x19\x03\x17 58910-S8330',
b'\xf1\x00LX ESC \x0b 102\x19\x05\x07 58910-S8330', b'\xf1\x00LX ESC \x0b 102\x19\x05\x07 58910-S8330',
b'\xf1\x00LX ESC \x0b 103\x19\t\t 58910-S8350',
b'\xf1\x00LX ESC \x0b 103\x19\t\x07 58910-S8330', b'\xf1\x00LX ESC \x0b 103\x19\t\x07 58910-S8330',
b'\xf1\x00LX ESC \x0b 103\x19\t\x10 58910-S8360', b'\xf1\x00LX ESC \x0b 103\x19\t\x10 58910-S8360',
b'\xf1\x00LX ESC \x0b 104 \x10\x16 58910-S8360', b'\xf1\x00LX ESC \x0b 104 \x10\x16 58910-S8360',
@ -794,6 +810,7 @@ FW_VERSIONS = {
], ],
(Ecu.eps, 0x7d4, None): [ (Ecu.eps, 0x7d4, None): [
b'\xf1\x00LX2 MDPS C 1,00 1,03 56310-S8020 4LXDC103', b'\xf1\x00LX2 MDPS C 1,00 1,03 56310-S8020 4LXDC103',
b'\xf1\x00LX2 MDPS C 1.00 1.03 56310-S8000 4LXDC103',
b'\xf1\x00LX2 MDPS C 1.00 1.03 56310-S8020 4LXDC103', b'\xf1\x00LX2 MDPS C 1.00 1.03 56310-S8020 4LXDC103',
b'\xf1\x00LX2 MDPS C 1.00 1.04 56310-S8020 4LXDC104', b'\xf1\x00LX2 MDPS C 1.00 1.04 56310-S8020 4LXDC104',
b'\xf1\x00ON MDPS C 1.00 1.00 56340-S9000 8B13', b'\xf1\x00ON MDPS C 1.00 1.00 56340-S9000 8B13',
@ -810,6 +827,7 @@ FW_VERSIONS = {
], ],
(Ecu.transmission, 0x7e1, None): [ (Ecu.transmission, 0x7e1, None): [
b'\xf1\x00bcsh8p54 U872\x00\x00\x00\x00\x00\x00TON4G38NB1\x96z28', b'\xf1\x00bcsh8p54 U872\x00\x00\x00\x00\x00\x00TON4G38NB1\x96z28',
b'\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB3X\xa8\xc08',
b'\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00TON4G38NB2[v\\\xb6', b'\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00TON4G38NB2[v\\\xb6',
b'\xf1\x87LBLUFN591307KF25vgvw\x97wwwy\x99\xa7\x99\x99\xaa\xa9\x9af\x88\x96h\x95o\xf7\xff\x99f/\xff\xe4c\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX2G38NB2\xd7\xc1/\xd1', b'\xf1\x87LBLUFN591307KF25vgvw\x97wwwy\x99\xa7\x99\x99\xaa\xa9\x9af\x88\x96h\x95o\xf7\xff\x99f/\xff\xe4c\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX2G38NB2\xd7\xc1/\xd1',
b'\xf1\x87LBLUFN650868KF36\xa9\x98\x89\x88\xa8\x88\x88\x88h\x99\xa6\x89fw\x86gw\x88\x97x\xaa\x7f\xf6\xff\xbb\xbb\x8f\xff+\x82\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX2G38NB3\xd1\xc3\xf8\xa8', b'\xf1\x87LBLUFN650868KF36\xa9\x98\x89\x88\xa8\x88\x88\x88h\x99\xa6\x89fw\x86gw\x88\x97x\xaa\x7f\xf6\xff\xbb\xbb\x8f\xff+\x82\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX2G38NB3\xd1\xc3\xf8\xa8',
@ -1186,6 +1204,23 @@ FW_VERSIONS = {
b'\xf1\x87\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf1\x816T6B8051\x00\x00\xf1\x006T6H0_C2\x00\x006T6B8051\x00\x00TJFSG24NH27\xa7\xc2\xb4', b'\xf1\x87\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf1\x816T6B8051\x00\x00\xf1\x006T6H0_C2\x00\x006T6B8051\x00\x00TJFSG24NH27\xa7\xc2\xb4',
], ],
}, },
CAR.ELANTRA: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00PD LKAS AT USA LHD 1.01 1.01 95740-G3100 A54',
],
(Ecu.transmission, 0x7e1, None): [
b'\xf1\x006U2V0_C2\x00\x006U2VA051\x00\x00DPD0H16NS0e\x0e\xcd\x8e',
],
(Ecu.eps, 0x7d4, None): [
b'\xf1\x00PD MDPS C 1.00 1.04 56310/G3300 4PDDC104',
],
(Ecu.abs, 0x7d1, None): [
b'\xf1\x00PD ESC \x0b 104\x18\t\x03 58920-G3350',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00PD__ SCC F-CUP 1.00 1.00 96400-G3300 ',
],
},
CAR.ELANTRA_2021: { CAR.ELANTRA_2021: {
(Ecu.fwdRadar, 0x7d0, None): [ (Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00CN7_ SCC F-CUP 1.00 1.01 99110-AA000 ', b'\xf1\x00CN7_ SCC F-CUP 1.00 1.01 99110-AA000 ',
@ -1321,15 +1356,6 @@ FW_VERSIONS = {
], ],
}, },
CAR.KIA_EV6: { CAR.KIA_EV6: {
(Ecu.abs, 0x7d1, None): [
b'\xf1\x00CV IEB \x02 101!\x10\x18 58520-CV100',
b'\xf1\x00CV IEB \x03 101!\x10\x18 58520-CV100',
b'\xf1\x8758520CV100\xf1\x00CV IEB \x02 101!\x10\x18 58520-CV100',
],
(Ecu.eps, 0x7d4, None): [
b'\xf1\x00CV1 MDPS R 1.00 1.04 57700-CV000 1B30',
b'\xf1\x00CV1 MDPS R 1.00 1.05 57700-CV000 2425',
],
(Ecu.fwdRadar, 0x7d0, None): [ (Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00CV1_ RDR ----- 1.00 1.01 99110-CV000 ', b'\xf1\x00CV1_ RDR ----- 1.00 1.01 99110-CV000 ',
b'\xf1\x8799110CV000\xf1\x00CV1_ RDR ----- 1.00 1.01 99110-CV000 ', b'\xf1\x8799110CV000\xf1\x00CV1_ RDR ----- 1.00 1.01 99110-CV000 ',
@ -1341,16 +1367,6 @@ FW_VERSIONS = {
], ],
}, },
CAR.IONIQ_5: { CAR.IONIQ_5: {
(Ecu.abs, 0x7d1, None): [
b'\xf1\x00NE1 IEB \x07 106!\x11) 58520-GI010',
b'\xf1\x8758520GI010\xf1\x00NE1 IEB \x07 106!\x11) 58520-GI010',
b'\xf1\x00NE1 IEB \x08 104!\x04\x05 58520-GI000',
b'\xf1\x8758520GI000\xf1\x00NE1 IEB \x08 104!\x04\x05 58520-GI000',
],
(Ecu.eps, 0x7d4, None): [
b'\xf1\x00NE MDPS R 1.00 1.06 57700GI000 4NEDR106',
b'\xf1\x8757700GI000 \xf1\x00NE MDPS R 1.00 1.06 57700GI000 4NEDR106',
],
(Ecu.fwdRadar, 0x7d0, None): [ (Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00NE1_ RDR ----- 1.00 1.00 99110-GI000 ', b'\xf1\x00NE1_ RDR ----- 1.00 1.00 99110-GI000 ',
b'\xf1\x8799110GI000\xf1\x00NE1_ RDR ----- 1.00 1.00 99110-GI000 ', b'\xf1\x8799110GI000\xf1\x00NE1_ RDR ----- 1.00 1.00 99110-GI000 ',
@ -1363,16 +1379,18 @@ FW_VERSIONS = {
CAR.TUCSON_HYBRID_4TH_GEN: { CAR.TUCSON_HYBRID_4TH_GEN: {
(Ecu.fwdCamera, 0x7c4, None): [ (Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N9240 14Q', b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N9240 14Q',
b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N9220 14K',
], ],
(Ecu.eps, 0x7d4, None): [ (Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00NX4 MDPS C 1.00 1.01 56300-P0100 2228', b'\xf1\x00NX4__ 1.00 1.00 99110-N9100 ',
], ],
(Ecu.engine, 0x7e0, None): [ },
b'\xf1\x87391312MND0', CAR.KIA_SPORTAGE_HYBRID_5TH_GEN: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1060 665',
], ],
(Ecu.transmission, 0x7e1, None): [ (Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00PSBG2441 G19_Rev\x00\x00\x00SNX4T16XXHS01NS2lS\xdfa', b'\xf1\x00NQ5__ 1.01 1.03 99110-CH000 ',
b'\xf1\x8795441-3D220\x00\xf1\x81G19_Rev\x00\x00\x00\xf1\x00PSBG2441 G19_Rev\x00\x00\x00SNX4T16XXHS01NS2lS\xdfa',
], ],
}, },
} }
@ -1384,20 +1402,20 @@ CHECKSUM = {
FEATURES = { FEATURES = {
# which message has the gear # which message has the gear
"use_cluster_gears": {CAR.ELANTRA, CAR.ELANTRA_GT_I30, CAR.KONA}, "use_cluster_gears": {CAR.ELANTRA, CAR.KONA},
"use_tcu_gears": {CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL, CAR.SONATA_LF, CAR.VELOSTER, CAR.TUCSON}, "use_tcu_gears": {CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL, CAR.SONATA_LF, CAR.VELOSTER, CAR.TUCSON},
"use_elect_gears": {CAR.KIA_NIRO_EV, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.KIA_OPTIMA_H, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.IONIQ, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.IONIQ_PHEV_2019, CAR.KONA_EV_2022}, "use_elect_gears": {CAR.KIA_NIRO_EV, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.KIA_OPTIMA_H, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.IONIQ, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.IONIQ_PHEV_2019, CAR.KONA_EV_2022},
# these cars use the FCA11 message for the AEB and FCW signals, all others use SCC12 # these cars use the FCA11 message for the AEB and FCW signals, all others use SCC12
"use_fca": {CAR.SONATA, CAR.SONATA_HYBRID, CAR.ELANTRA, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.ELANTRA_GT_I30, CAR.KIA_STINGER, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KONA_EV, CAR.KIA_FORTE, CAR.KIA_NIRO_EV, CAR.PALISADE, CAR.GENESIS_G70, CAR.GENESIS_G70_2020, CAR.KONA, CAR.SANTA_FE, CAR.KIA_SELTOS, CAR.KONA_HEV, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.TUCSON, CAR.KONA_EV_2022}, "use_fca": {CAR.SONATA, CAR.SONATA_HYBRID, CAR.ELANTRA, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.KIA_STINGER, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KONA_EV, CAR.KIA_FORTE, CAR.KIA_NIRO_EV, CAR.PALISADE, CAR.GENESIS_G70, CAR.GENESIS_G70_2020, CAR.KONA, CAR.SANTA_FE, CAR.KIA_SELTOS, CAR.KONA_HEV, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.TUCSON, CAR.KONA_EV_2022},
} }
CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5, CAR.TUCSON_HYBRID_4TH_GEN} CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN}
# The camera does SCC on these cars, rather than the radar # The camera does SCC on these cars, rather than the radar
CAMERA_SCC_CAR = {CAR.KONA_EV_2022, } CAMERA_SCC_CAR = {CAR.KONA_EV_2022, }
HYBRID_CAR = {CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.IONIQ, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.IONIQ_PHEV_2019, CAR.TUCSON_HYBRID_4TH_GEN} # these cars use a different gas signal HYBRID_CAR = {CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.IONIQ, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.IONIQ_PHEV_2019, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN} # these cars use a different gas signal
EV_CAR = {CAR.IONIQ_EV_2020, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.KIA_NIRO_EV, CAR.KONA_EV_2022, CAR.KIA_EV6, CAR.IONIQ_5} EV_CAR = {CAR.IONIQ_EV_2020, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.KIA_NIRO_EV, CAR.KONA_EV_2022, CAR.KIA_EV6, CAR.IONIQ_5}
# these cars require a special panda safety mode due to missing counters and checksums in the messages # these cars require a special panda safety mode due to missing counters and checksums in the messages
@ -1409,7 +1427,6 @@ DBC = {
CAR.ELANTRA: dbc_dict('hyundai_kia_generic', None), CAR.ELANTRA: dbc_dict('hyundai_kia_generic', None),
CAR.ELANTRA_2021: dbc_dict('hyundai_kia_generic', None), CAR.ELANTRA_2021: dbc_dict('hyundai_kia_generic', None),
CAR.ELANTRA_HEV_2021: dbc_dict('hyundai_kia_generic', None), CAR.ELANTRA_HEV_2021: dbc_dict('hyundai_kia_generic', None),
CAR.ELANTRA_GT_I30: dbc_dict('hyundai_kia_generic', None),
CAR.GENESIS_G70: dbc_dict('hyundai_kia_generic', None), CAR.GENESIS_G70: dbc_dict('hyundai_kia_generic', None),
CAR.GENESIS_G70_2020: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'), CAR.GENESIS_G70_2020: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'),
CAR.GENESIS_G80: dbc_dict('hyundai_kia_generic', None), CAR.GENESIS_G80: dbc_dict('hyundai_kia_generic', None),
@ -1450,4 +1467,5 @@ DBC = {
CAR.SONATA_HYBRID: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'), CAR.SONATA_HYBRID: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'),
CAR.TUCSON_HYBRID_4TH_GEN: dbc_dict('hyundai_canfd', None), CAR.TUCSON_HYBRID_4TH_GEN: dbc_dict('hyundai_canfd', None),
CAR.IONIQ_5: dbc_dict('hyundai_canfd', None), CAR.IONIQ_5: dbc_dict('hyundai_canfd', None),
CAR.KIA_SPORTAGE_HYBRID_5TH_GEN: dbc_dict('hyundai_canfd', None),
} }

@ -43,7 +43,7 @@ CAR_INFO: Dict[str, Union[MazdaCarInfo, List[MazdaCarInfo]]] = {
CAR.MAZDA3: MazdaCarInfo("Mazda 3 2017-18"), CAR.MAZDA3: MazdaCarInfo("Mazda 3 2017-18"),
CAR.MAZDA6: MazdaCarInfo("Mazda 6 2017-20"), CAR.MAZDA6: MazdaCarInfo("Mazda 6 2017-20"),
CAR.CX9_2021: MazdaCarInfo("Mazda CX-9 2021-22", video_link="https://youtu.be/dA3duO4a0O4"), CAR.CX9_2021: MazdaCarInfo("Mazda CX-9 2021-22", video_link="https://youtu.be/dA3duO4a0O4"),
CAR.CX5_2022: MazdaCarInfo("Mazda CX-5 2022"), CAR.CX5_2022: MazdaCarInfo("Mazda CX-5 2022-23"),
} }
@ -89,6 +89,7 @@ FW_VERSIONS = {
], ],
(Ecu.fwdCamera, 0x706, None): [ (Ecu.fwdCamera, 0x706, None): [
b'GSH7-67XK2-S\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'GSH7-67XK2-S\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'GSH7-67XK2-T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.transmission, 0x7e1, None): [ (Ecu.transmission, 0x7e1, None): [
b'PYB2-21PS1-H\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'PYB2-21PS1-H\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
@ -98,13 +99,15 @@ FW_VERSIONS = {
}, },
CAR.CX5: { CAR.CX5: {
(Ecu.eps, 0x730, None): [ (Ecu.eps, 0x730, None): [
b'K319-3210X-A-00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'KCB8-3210X-B-00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'KJ01-3210X-G-00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'KJ01-3210X-G-00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'KJ01-3210X-J-00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'KJ01-3210X-J-00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'KJ01-3210X-M-00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'KJ01-3210X-M-00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'K319-3210X-A-00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.engine, 0x7e0, None): [ (Ecu.engine, 0x7e0, None): [
b'PA53-188K2-A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'PA53-188K2-A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PAR4-188K2-E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PYFA-188K2-J\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'PYFA-188K2-J\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PYFC-188K2-J\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'PYFC-188K2-J\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PYFD-188K2-J\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'PYFD-188K2-J\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
@ -146,6 +149,7 @@ FW_VERSIONS = {
], ],
(Ecu.transmission, 0x7e1, None): [ (Ecu.transmission, 0x7e1, None): [
b'PA66-21PS1-A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'PA66-21PS1-A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PA66-21PS1-D\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PX39-21PS1-B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'PX39-21PS1-B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PX39-21PS1-D\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'PX39-21PS1-D\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PX68-21PS1-B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'PX68-21PS1-B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',

@ -23,7 +23,6 @@ non_tested_cars = [
GM.MALIBU, GM.MALIBU,
GM.EQUINOX, GM.EQUINOX,
GM.BOLT_EV, GM.BOLT_EV,
HYUNDAI.ELANTRA_GT_I30,
HYUNDAI.GENESIS_G90, HYUNDAI.GENESIS_G90,
HYUNDAI.KIA_OPTIMA_H, HYUNDAI.KIA_OPTIMA_H,
] ]
@ -91,13 +90,14 @@ routes = [
CarTestRoute("7653b2bce7bcfdaa|2020-03-04--15-34-32", HYUNDAI.KIA_OPTIMA_G4), CarTestRoute("7653b2bce7bcfdaa|2020-03-04--15-34-32", HYUNDAI.KIA_OPTIMA_G4),
CarTestRoute("018654717bc93d7d|2022-09-19--23-11-10", HYUNDAI.KIA_OPTIMA_G4_FL, segment=0), CarTestRoute("018654717bc93d7d|2022-09-19--23-11-10", HYUNDAI.KIA_OPTIMA_G4_FL, segment=0),
CarTestRoute("c75a59efa0ecd502|2021-03-11--20-52-55", HYUNDAI.KIA_SELTOS), CarTestRoute("c75a59efa0ecd502|2021-03-11--20-52-55", HYUNDAI.KIA_SELTOS),
CarTestRoute("b3537035ffe6a7d6|2022-10-17--15-23-49", HYUNDAI.KIA_SPORTAGE_HYBRID_5TH_GEN),
CarTestRoute("5b7c365c50084530|2020-04-15--16-13-24", HYUNDAI.SONATA), CarTestRoute("5b7c365c50084530|2020-04-15--16-13-24", HYUNDAI.SONATA),
CarTestRoute("b2a38c712dcf90bd|2020-05-18--18-12-48", HYUNDAI.SONATA_LF), CarTestRoute("b2a38c712dcf90bd|2020-05-18--18-12-48", HYUNDAI.SONATA_LF),
CarTestRoute("fb3fd42f0baaa2f8|2022-03-30--15-25-05", HYUNDAI.TUCSON), CarTestRoute("fb3fd42f0baaa2f8|2022-03-30--15-25-05", HYUNDAI.TUCSON),
CarTestRoute("36e10531feea61a4|2022-07-25--13-37-42", HYUNDAI.TUCSON_HYBRID_4TH_GEN), CarTestRoute("36e10531feea61a4|2022-07-25--13-37-42", HYUNDAI.TUCSON_HYBRID_4TH_GEN),
CarTestRoute("5875672fc1d4bf57|2020-07-23--21-33-28", HYUNDAI.KIA_SORENTO), CarTestRoute("5875672fc1d4bf57|2020-07-23--21-33-28", HYUNDAI.KIA_SORENTO),
CarTestRoute("9c917ba0d42ffe78|2020-04-17--12-43-19", HYUNDAI.PALISADE), CarTestRoute("9c917ba0d42ffe78|2020-04-17--12-43-19", HYUNDAI.PALISADE),
CarTestRoute("22de8111a8c5463c|2022-07-29--13-34-49", HYUNDAI.IONIQ_5), CarTestRoute("05a8f0197fdac372|2022-10-19--14-14-09", HYUNDAI.IONIQ_5), # HDA2
CarTestRoute("3f29334d6134fcd4|2022-03-30--22-00-50", HYUNDAI.IONIQ_PHEV_2019), CarTestRoute("3f29334d6134fcd4|2022-03-30--22-00-50", HYUNDAI.IONIQ_PHEV_2019),
CarTestRoute("fa8db5869167f821|2021-06-10--22-50-10", HYUNDAI.IONIQ_PHEV), CarTestRoute("fa8db5869167f821|2021-06-10--22-50-10", HYUNDAI.IONIQ_PHEV),
CarTestRoute("2c5cf2dd6102e5da|2020-12-17--16-06-44", HYUNDAI.IONIQ_EV_2020), CarTestRoute("2c5cf2dd6102e5da|2020-12-17--16-06-44", HYUNDAI.IONIQ_EV_2020),
@ -110,7 +110,7 @@ routes = [
CarTestRoute("49f3c13141b6bc87|2021-07-28--08-05-13", HYUNDAI.KONA_HEV), CarTestRoute("49f3c13141b6bc87|2021-07-28--08-05-13", HYUNDAI.KONA_HEV),
CarTestRoute("5dddcbca6eb66c62|2020-07-26--13-24-19", HYUNDAI.KIA_STINGER), CarTestRoute("5dddcbca6eb66c62|2020-07-26--13-24-19", HYUNDAI.KIA_STINGER),
CarTestRoute("d624b3d19adce635|2020-08-01--14-59-12", HYUNDAI.VELOSTER), CarTestRoute("d624b3d19adce635|2020-08-01--14-59-12", HYUNDAI.VELOSTER),
CarTestRoute("d824e27e8c60172c|2022-05-19--16-15-28", HYUNDAI.KIA_EV6), # HDA2 CarTestRoute("d545129f3ca90f28|2022-10-19--09-22-54", HYUNDAI.KIA_EV6), # HDA2
CarTestRoute("68d6a96e703c00c9|2022-09-10--16-09-39", HYUNDAI.KIA_EV6), # HDA1 CarTestRoute("68d6a96e703c00c9|2022-09-10--16-09-39", HYUNDAI.KIA_EV6), # HDA1
CarTestRoute("007d5e4ad9f86d13|2021-09-30--15-09-23", HYUNDAI.KIA_K5_2021), CarTestRoute("007d5e4ad9f86d13|2021-09-30--15-09-23", HYUNDAI.KIA_K5_2021),
CarTestRoute("50c6c9b85fd1ff03|2020-10-26--17-56-06", HYUNDAI.KIA_NIRO_EV), CarTestRoute("50c6c9b85fd1ff03|2020-10-26--17-56-06", HYUNDAI.KIA_NIRO_EV),
@ -118,6 +118,7 @@ routes = [
CarTestRoute("34a875f29f69841a|2021-07-29--13-02-09", HYUNDAI.KIA_NIRO_HEV_2021), CarTestRoute("34a875f29f69841a|2021-07-29--13-02-09", HYUNDAI.KIA_NIRO_HEV_2021),
CarTestRoute("50a2212c41f65c7b|2021-05-24--16-22-06", HYUNDAI.KIA_FORTE), CarTestRoute("50a2212c41f65c7b|2021-05-24--16-22-06", HYUNDAI.KIA_FORTE),
CarTestRoute("c5ac319aa9583f83|2021-06-01--18-18-31", HYUNDAI.ELANTRA), CarTestRoute("c5ac319aa9583f83|2021-06-01--18-18-31", HYUNDAI.ELANTRA),
CarTestRoute("734ef96182ddf940|2022-10-02--16-41-44", HYUNDAI.ELANTRA), # 2019 Elantra GT
CarTestRoute("82e9cdd3f43bf83e|2021-05-15--02-42-51", HYUNDAI.ELANTRA_2021), CarTestRoute("82e9cdd3f43bf83e|2021-05-15--02-42-51", HYUNDAI.ELANTRA_2021),
CarTestRoute("715ac05b594e9c59|2021-06-20--16-21-07", HYUNDAI.ELANTRA_HEV_2021), CarTestRoute("715ac05b594e9c59|2021-06-20--16-21-07", HYUNDAI.ELANTRA_HEV_2021),
CarTestRoute("7120aa90bbc3add7|2021-08-02--07-12-31", HYUNDAI.SONATA_HYBRID), CarTestRoute("7120aa90bbc3add7|2021-08-02--07-12-31", HYUNDAI.SONATA_HYBRID),

@ -1,6 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import random import random
import unittest import unittest
from collections import defaultdict
from parameterized import parameterized from parameterized import parameterized
from cereal import car from cereal import car
@ -44,7 +45,18 @@ class TestFwFingerprint(unittest.TestCase):
duplicates = {fw for fw in ecu_fw if ecu_fw.count(fw) > 1} duplicates = {fw for fw in ecu_fw if ecu_fw.count(fw) > 1}
self.assertFalse(len(duplicates), f"{car_model}: Duplicate FW versions: Ecu.{ECU_NAME[ecu[0]]}, {duplicates}") self.assertFalse(len(duplicates), f"{car_model}: Duplicate FW versions: Ecu.{ECU_NAME[ecu[0]]}, {duplicates}")
def test_all_addrs_map_to_one_ecu(self):
for brand, cars in VERSIONS.items():
addr_to_ecu = defaultdict(set)
for ecus in cars.values():
for ecu_type, addr, sub_addr in ecus.keys():
addr_to_ecu[(addr, sub_addr)].add(ecu_type)
ecus_for_addr = addr_to_ecu[(addr, sub_addr)]
ecu_strings = ", ".join([f'Ecu.{ECU_NAME[ecu]}' for ecu in ecus_for_addr])
self.assertLessEqual(len(ecus_for_addr), 1, f"{brand} has multiple ECUs that map to one address: {ecu_strings} -> ({hex(addr)}, {sub_addr})")
def test_data_collection_ecus(self): def test_data_collection_ecus(self):
# Asserts no extra ECUs are in the fingerprinting database
for brand, config in FW_QUERY_CONFIGS.items(): for brand, config in FW_QUERY_CONFIGS.items():
for car_model, ecus in VERSIONS[brand].items(): for car_model, ecus in VERSIONS[brand].items():
bad_ecus = set(ecus).intersection(config.extra_ecus) bad_ecus = set(ecus).intersection(config.extra_ecus)
@ -80,10 +92,11 @@ class TestFwFingerprint(unittest.TestCase):
def test_fw_request_ecu_whitelist(self): def test_fw_request_ecu_whitelist(self):
for brand, config in FW_QUERY_CONFIGS.items(): for brand, config in FW_QUERY_CONFIGS.items():
with self.subTest(brand=brand): with self.subTest(brand=brand):
whitelisted_ecus = set([ecu for r in config.requests for ecu in r.whitelist_ecus]) whitelisted_ecus = {ecu for r in config.requests for ecu in r.whitelist_ecus}
brand_ecus = set([fw[0] for car_fw in VERSIONS[brand].values() for fw in car_fw]) brand_ecus = {fw[0] for car_fw in VERSIONS[brand].values() for fw in car_fw}
brand_ecus |= {ecu[0] for ecu in config.extra_ecus}
# each ecu in brand's fw versions needs to be whitelisted at least once # each ecu in brand's fw versions + extra ecus needs to be whitelisted at least once
ecus_not_whitelisted = brand_ecus - whitelisted_ecus ecus_not_whitelisted = brand_ecus - whitelisted_ecus
ecu_strings = ", ".join([f'Ecu.{ECU_NAME[ecu]}' for ecu in ecus_not_whitelisted]) ecu_strings = ", ".join([f'Ecu.{ECU_NAME[ecu]}' for ecu in ecus_not_whitelisted])

@ -234,7 +234,7 @@ class TestCarModelBase(unittest.TestCase):
checks['gasPressed'] += CS.gasPressed != self.safety.get_gas_pressed_prev() checks['gasPressed'] += CS.gasPressed != self.safety.get_gas_pressed_prev()
checks['cruiseState'] += CS.cruiseState.enabled and not CS.cruiseState.available checks['cruiseState'] += CS.cruiseState.enabled and not CS.cruiseState.available
if self.CP.carName not in ("hyundai", "volkswagen", "gm", "body"): if self.CP.carName not in ("hyundai", "volkswagen", "body"):
# TODO: fix standstill mismatches for other makes # TODO: fix standstill mismatches for other makes
checks['standstill'] += CS.standstill == self.safety.get_vehicle_moving() checks['standstill'] += CS.standstill == self.safety.get_vehicle_moving()

@ -32,6 +32,7 @@ CHEVROLET EQUINOX 2019: [2.0, 2.0, 0.05]
VOLKSWAGEN PASSAT NMS: [2.5, 2.5, 0.1] VOLKSWAGEN PASSAT NMS: [2.5, 2.5, 0.1]
VOLKSWAGEN SHARAN 2ND GEN: [2.5, 2.5, 0.1] VOLKSWAGEN SHARAN 2ND GEN: [2.5, 2.5, 0.1]
HYUNDAI TUCSON HYBRID 4TH GEN: [2.5, 2.5, 0.0] HYUNDAI TUCSON HYBRID 4TH GEN: [2.5, 2.5, 0.0]
KIA SPORTAGE HYBRID 5TH GEN: [2.5, 2.5, 0.0]
# Dashcam or fallback configured as ideal car # Dashcam or fallback configured as ideal car
mock: [10.0, 10, 0.0] mock: [10.0, 10, 0.0]

@ -35,7 +35,7 @@ HYUNDAI SANTA FE 2019: [3.0787027729757632, 2.6173437483495565, 0.12070193418239
HYUNDAI SANTA FE HYBRID 2022: [3.501877602644835, 2.729064118456137, 0.10384068104538963] HYUNDAI SANTA FE HYBRID 2022: [3.501877602644835, 2.729064118456137, 0.10384068104538963]
HYUNDAI SANTA FE PlUG-IN HYBRID 2022: [1.6953050513611045, 1.5837614296206861, 0.12672855941458458] HYUNDAI SANTA FE PlUG-IN HYBRID 2022: [1.6953050513611045, 1.5837614296206861, 0.12672855941458458]
HYUNDAI SONATA 2019: [2.2200457811703953, 1.2967330275895228, 0.14039920986586393] HYUNDAI SONATA 2019: [2.2200457811703953, 1.2967330275895228, 0.14039920986586393]
HYUNDAI SONATA 2020: [3.284505627881726, 2.1259108157250735, 0.08452048323586728] HYUNDAI SONATA 2020: [2.9638737459977467, 2.1259108157250735, 0.07813665616927593]
HYUNDAI SONATA HYBRID 2021: [2.8990264092395734, 2.061410192222139, 0.0899805488717382] HYUNDAI SONATA HYBRID 2021: [2.8990264092395734, 2.061410192222139, 0.0899805488717382]
JEEP GRAND CHEROKEE 2019: [1.7321233388827006, 1.289689569171081, 0.15046331002097185] JEEP GRAND CHEROKEE 2019: [1.7321233388827006, 1.289689569171081, 0.15046331002097185]
JEEP GRAND CHEROKEE V6 2018: [1.8776598027756923, 1.4057367824262523, 0.11725947414922003] JEEP GRAND CHEROKEE V6 2018: [1.8776598027756923, 1.4057367824262523, 0.11725947414922003]
@ -67,8 +67,8 @@ TOYOTA CAMRY 2021: [2.6922769557433055, 2.3476510120007434, 0.1450430192989234]
TOYOTA CAMRY HYBRID 2018: [2.0974120828287774, 1.7996193116697359, 0.13823613467632756] TOYOTA CAMRY HYBRID 2018: [2.0974120828287774, 1.7996193116697359, 0.13823613467632756]
TOYOTA CAMRY HYBRID 2021: [2.6426668350384457, 2.3901492458927986, 0.16103875108816076] TOYOTA CAMRY HYBRID 2021: [2.6426668350384457, 2.3901492458927986, 0.16103875108816076]
TOYOTA COROLLA 2017: [3.117154369115421, 1.8438132575043773, 0.12289685869250652] TOYOTA COROLLA 2017: [3.117154369115421, 1.8438132575043773, 0.12289685869250652]
TOYOTA COROLLA HYBRID TSS2 2019: [2.3287672277252005, 1.8118712531729109, 0.2215868445753317] TOYOTA COROLLA HYBRID TSS2 2019: [1.9079729107361805, 1.8118712531729109, 0.22251440891543514]
TOYOTA COROLLA TSS2 2019: [2.4204464833010175, 1.9258612322678952, 0.20670411068012526] TOYOTA COROLLA TSS2 2019: [2.0742917676766712, 1.9258612322678952, 0.16888685704519352]
TOYOTA HIGHLANDER 2017: [1.8696367437248915, 1.626293990451463, 0.17485372210240796] TOYOTA HIGHLANDER 2017: [1.8696367437248915, 1.626293990451463, 0.17485372210240796]
TOYOTA HIGHLANDER 2020: [2.022340166827233, 1.6183134804881791, 0.14592306380054457] TOYOTA HIGHLANDER 2020: [2.022340166827233, 1.6183134804881791, 0.14592306380054457]
TOYOTA HIGHLANDER HYBRID 2018: [1.9421825202382728, 1.6433903296845025, 0.16928956792275918] TOYOTA HIGHLANDER HYBRID 2018: [1.9421825202382728, 1.6433903296845025, 0.16928956792275918]

@ -26,7 +26,6 @@ KIA SELTOS 2021: HYUNDAI SONATA 2020
KIA NIRO HYBRID 2019: KIA NIRO EV 2020 KIA NIRO HYBRID 2019: KIA NIRO EV 2020
KIA NIRO HYBRID 2021: KIA NIRO EV 2020 KIA NIRO HYBRID 2021: KIA NIRO EV 2020
HYUNDAI VELOSTER 2019: HYUNDAI SONATA 2019 HYUNDAI VELOSTER 2019: HYUNDAI SONATA 2019
HYUNDAI I30 N LINE 2019 & GT 2018 DCT: HYUNDAI SONATA 2019
HYUNDAI KONA 2020: HYUNDAI KONA ELECTRIC 2019 HYUNDAI KONA 2020: HYUNDAI KONA ELECTRIC 2019
HYUNDAI KONA HYBRID 2020: HYUNDAI KONA ELECTRIC 2019 HYUNDAI KONA HYBRID 2020: HYUNDAI KONA ELECTRIC 2019
HYUNDAI KONA ELECTRIC 2022: HYUNDAI KONA ELECTRIC 2019 HYUNDAI KONA ELECTRIC 2022: HYUNDAI KONA ELECTRIC 2019

@ -2,7 +2,6 @@
from cereal import car from cereal import car
from common.conversions import Conversions as CV from common.conversions import Conversions as CV
from panda import Panda from panda import Panda
from selfdrive.car.toyota.tunes import LatTunes, LongTunes, set_long_tune, set_lat_tune
from selfdrive.car.toyota.values import Ecu, CAR, ToyotaFlags, TSS2_CAR, RADAR_ACC_CAR, NO_DSU_CAR, MIN_ACC_SPEED, EPS_SCALE, EV_HYBRID_CAR, CarControllerParams from selfdrive.car.toyota.values import Ecu, CAR, ToyotaFlags, TSS2_CAR, RADAR_ACC_CAR, NO_DSU_CAR, MIN_ACC_SPEED, EPS_SCALE, EV_HYBRID_CAR, CarControllerParams
from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config
from selfdrive.car.interfaces import CarInterfaceBase from selfdrive.car.interfaces import CarInterfaceBase
@ -74,7 +73,6 @@ class CarInterface(CarInterfaceBase):
ret.wheelSpeedFactor = 1.035 ret.wheelSpeedFactor = 1.035
tire_stiffness_factor = 0.5533 tire_stiffness_factor = 0.5533
ret.mass = 4481. * CV.LB_TO_KG + STD_CARGO_KG # mean between min and max ret.mass = 4481. * CV.LB_TO_KG + STD_CARGO_KG # mean between min and max
set_lat_tune(ret.lateralTuning, LatTunes.PID_C)
elif candidate in (CAR.CHR, CAR.CHRH): elif candidate in (CAR.CHR, CAR.CHRH):
stop_and_go = True stop_and_go = True
@ -82,7 +80,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 13.6 ret.steerRatio = 13.6
tire_stiffness_factor = 0.7933 tire_stiffness_factor = 0.7933
ret.mass = 3300. * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 3300. * CV.LB_TO_KG + STD_CARGO_KG
set_lat_tune(ret.lateralTuning, LatTunes.PID_F)
elif candidate in (CAR.CAMRY, CAR.CAMRYH, CAR.CAMRY_TSS2, CAR.CAMRYH_TSS2): elif candidate in (CAR.CAMRY, CAR.CAMRYH, CAR.CAMRY_TSS2, CAR.CAMRYH_TSS2):
stop_and_go = True stop_and_go = True
@ -90,8 +87,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 13.7 ret.steerRatio = 13.7
tire_stiffness_factor = 0.7933 tire_stiffness_factor = 0.7933
ret.mass = 3400. * CV.LB_TO_KG + STD_CARGO_KG # mean between normal and hybrid ret.mass = 3400. * CV.LB_TO_KG + STD_CARGO_KG # mean between normal and hybrid
if candidate not in (CAR.CAMRY_TSS2, CAR.CAMRYH_TSS2):
set_lat_tune(ret.lateralTuning, LatTunes.PID_C)
elif candidate in (CAR.HIGHLANDER, CAR.HIGHLANDERH, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2): elif candidate in (CAR.HIGHLANDER, CAR.HIGHLANDERH, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2):
stop_and_go = True stop_and_go = True
@ -99,7 +94,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 16.0 ret.steerRatio = 16.0
tire_stiffness_factor = 0.8 tire_stiffness_factor = 0.8
ret.mass = 4516. * CV.LB_TO_KG + STD_CARGO_KG # mean between normal and hybrid ret.mass = 4516. * CV.LB_TO_KG + STD_CARGO_KG # mean between normal and hybrid
set_lat_tune(ret.lateralTuning, LatTunes.PID_G)
elif candidate in (CAR.AVALON, CAR.AVALON_2019, CAR.AVALONH_2019, CAR.AVALON_TSS2, CAR.AVALONH_TSS2): elif candidate in (CAR.AVALON, CAR.AVALON_2019, CAR.AVALONH_2019, CAR.AVALON_TSS2, CAR.AVALONH_TSS2):
# starting from 2019, all Avalon variants have stop and go # starting from 2019, all Avalon variants have stop and go
@ -109,7 +103,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 14.8 # Found at https://pressroom.toyota.com/releases/2016+avalon+product+specs.download ret.steerRatio = 14.8 # Found at https://pressroom.toyota.com/releases/2016+avalon+product+specs.download
tire_stiffness_factor = 0.7983 tire_stiffness_factor = 0.7983
ret.mass = 3505. * CV.LB_TO_KG + STD_CARGO_KG # mean between normal and hybrid ret.mass = 3505. * CV.LB_TO_KG + STD_CARGO_KG # mean between normal and hybrid
set_lat_tune(ret.lateralTuning, LatTunes.PID_H)
elif candidate in (CAR.RAV4_TSS2, CAR.RAV4_TSS2_2022, CAR.RAV4H_TSS2, CAR.RAV4H_TSS2_2022): elif candidate in (CAR.RAV4_TSS2, CAR.RAV4_TSS2_2022, CAR.RAV4H_TSS2, CAR.RAV4H_TSS2_2022):
stop_and_go = True stop_and_go = True
@ -117,14 +110,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 14.3 ret.steerRatio = 14.3
tire_stiffness_factor = 0.7933 tire_stiffness_factor = 0.7933
ret.mass = 3585. * CV.LB_TO_KG + STD_CARGO_KG # Average between ICE and Hybrid ret.mass = 3585. * CV.LB_TO_KG + STD_CARGO_KG # Average between ICE and Hybrid
set_lat_tune(ret.lateralTuning, LatTunes.PID_D)
# 2019+ RAV4 TSS2 uses two different steering racks and specific tuning seems to be necessary.
# See https://github.com/commaai/openpilot/pull/21429#issuecomment-873652891
for fw in car_fw:
if fw.ecu == "eps" and (fw.fwVersion.startswith(b'\x02') or fw.fwVersion in [b'8965B42181\x00\x00\x00\x00\x00\x00']):
set_lat_tune(ret.lateralTuning, LatTunes.PID_I)
break
elif candidate in (CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2): elif candidate in (CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2):
stop_and_go = True stop_and_go = True
@ -139,7 +124,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 16.0 # not optimized ret.steerRatio = 16.0 # not optimized
tire_stiffness_factor = 0.444 # not optimized yet tire_stiffness_factor = 0.444 # not optimized yet
ret.mass = 3677. * CV.LB_TO_KG + STD_CARGO_KG # mean between min and max ret.mass = 3677. * CV.LB_TO_KG + STD_CARGO_KG # mean between min and max
set_lat_tune(ret.lateralTuning, LatTunes.PID_D)
elif candidate == CAR.SIENNA: elif candidate == CAR.SIENNA:
stop_and_go = True stop_and_go = True
@ -147,14 +131,12 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 15.5 ret.steerRatio = 15.5
tire_stiffness_factor = 0.444 tire_stiffness_factor = 0.444
ret.mass = 4590. * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 4590. * CV.LB_TO_KG + STD_CARGO_KG
set_lat_tune(ret.lateralTuning, LatTunes.PID_J)
elif candidate in (CAR.LEXUS_IS, CAR.LEXUS_RC): elif candidate in (CAR.LEXUS_IS, CAR.LEXUS_RC):
ret.wheelbase = 2.79908 ret.wheelbase = 2.79908
ret.steerRatio = 13.3 ret.steerRatio = 13.3
tire_stiffness_factor = 0.444 tire_stiffness_factor = 0.444
ret.mass = 3736.8 * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 3736.8 * CV.LB_TO_KG + STD_CARGO_KG
set_lat_tune(ret.lateralTuning, LatTunes.PID_L)
elif candidate == CAR.LEXUS_CTH: elif candidate == CAR.LEXUS_CTH:
stop_and_go = True stop_and_go = True
@ -162,7 +144,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 18.6 ret.steerRatio = 18.6
tire_stiffness_factor = 0.517 tire_stiffness_factor = 0.517
ret.mass = 3108 * CV.LB_TO_KG + STD_CARGO_KG # mean between min and max ret.mass = 3108 * CV.LB_TO_KG + STD_CARGO_KG # mean between min and max
set_lat_tune(ret.lateralTuning, LatTunes.PID_M)
elif candidate in (CAR.LEXUS_NX, CAR.LEXUS_NXH, CAR.LEXUS_NX_TSS2, CAR.LEXUS_NXH_TSS2): elif candidate in (CAR.LEXUS_NX, CAR.LEXUS_NXH, CAR.LEXUS_NX_TSS2, CAR.LEXUS_NXH_TSS2):
stop_and_go = True stop_and_go = True
@ -170,7 +151,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 14.7 ret.steerRatio = 14.7
tire_stiffness_factor = 0.444 # not optimized yet tire_stiffness_factor = 0.444 # not optimized yet
ret.mass = 4070 * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 4070 * CV.LB_TO_KG + STD_CARGO_KG
set_lat_tune(ret.lateralTuning, LatTunes.PID_C)
elif candidate == CAR.PRIUS_TSS2: elif candidate == CAR.PRIUS_TSS2:
stop_and_go = True stop_and_go = True
@ -178,7 +158,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 13.4 # True steerRatio from older prius ret.steerRatio = 13.4 # True steerRatio from older prius
tire_stiffness_factor = 0.6371 # hand-tune tire_stiffness_factor = 0.6371 # hand-tune
ret.mass = 3115. * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 3115. * CV.LB_TO_KG + STD_CARGO_KG
set_lat_tune(ret.lateralTuning, LatTunes.PID_N)
elif candidate == CAR.MIRAI: elif candidate == CAR.MIRAI:
stop_and_go = True stop_and_go = True
@ -186,7 +165,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 14.8 ret.steerRatio = 14.8
tire_stiffness_factor = 0.8 tire_stiffness_factor = 0.8
ret.mass = 4300. * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 4300. * CV.LB_TO_KG + STD_CARGO_KG
set_lat_tune(ret.lateralTuning, LatTunes.PID_C)
elif candidate in (CAR.ALPHARD_TSS2, CAR.ALPHARDH_TSS2): elif candidate in (CAR.ALPHARD_TSS2, CAR.ALPHARDH_TSS2):
stop_and_go = True stop_and_go = True
@ -194,7 +172,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 14.2 ret.steerRatio = 14.2
tire_stiffness_factor = 0.444 tire_stiffness_factor = 0.444
ret.mass = 4305. * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 4305. * CV.LB_TO_KG + STD_CARGO_KG
set_lat_tune(ret.lateralTuning, LatTunes.PID_J)
ret.centerToFront = ret.wheelbase * 0.44 ret.centerToFront = ret.wheelbase * 0.44
@ -230,12 +207,23 @@ class CarInterface(CarInterfaceBase):
# to a negative value, so it won't matter. # to a negative value, so it won't matter.
ret.minEnableSpeed = -1. if (stop_and_go or ret.enableGasInterceptor) else MIN_ACC_SPEED ret.minEnableSpeed = -1. if (stop_and_go or ret.enableGasInterceptor) else MIN_ACC_SPEED
tune = ret.longitudinalTuning
if candidate in TSS2_CAR or ret.enableGasInterceptor: if candidate in TSS2_CAR or ret.enableGasInterceptor:
set_long_tune(ret.longitudinalTuning, LongTunes.TSS2) tune.deadzoneBP = [0., 8.05]
tune.deadzoneV = [.0, .14]
tune.kpBP = [0., 5., 20.]
tune.kpV = [1.3, 1.0, 0.7]
tune.kiBP = [0., 5., 12., 20., 27.]
tune.kiV = [.35, .23, .20, .17, .1]
if candidate in TSS2_CAR: if candidate in TSS2_CAR:
ret.stoppingDecelRate = 0.3 # reach stopping target smoothly ret.stoppingDecelRate = 0.3 # reach stopping target smoothly
else: else:
set_long_tune(ret.longitudinalTuning, LongTunes.TSS) tune.deadzoneBP = [0., 9.]
tune.deadzoneV = [.0, .15]
tune.kpBP = [0., 5., 35.]
tune.kiBP = [0., 35.]
tune.kpV = [3.6, 2.4, 1.5]
tune.kiV = [0.54, 0.36]
return ret return ret

@ -1,102 +0,0 @@
#!/usr/bin/env python3
from enum import Enum
class LongTunes(Enum):
TSS2 = 0
TSS = 1
class LatTunes(Enum):
INDI_PRIUS = 0
LQR_RAV4 = 1
PID_A = 2
PID_B = 3
PID_C = 4
PID_D = 5
PID_E = 6
PID_F = 7
PID_G = 8
PID_I = 9
PID_H = 10
PID_J = 11
PID_K = 12
PID_L = 13
PID_M = 14
PID_N = 15
###### LONG ######
def set_long_tune(tune, name):
# Improved longitudinal tune
if name == LongTunes.TSS2:
tune.deadzoneBP = [0., 8.05]
tune.deadzoneV = [.0, .14]
tune.kpBP = [0., 5., 20.]
tune.kpV = [1.3, 1.0, 0.7]
tune.kiBP = [0., 5., 12., 20., 27.]
tune.kiV = [.35, .23, .20, .17, .1]
# Default longitudinal tune
elif name == LongTunes.TSS:
tune.deadzoneBP = [0., 9.]
tune.deadzoneV = [.0, .15]
tune.kpBP = [0., 5., 35.]
tune.kiBP = [0., 35.]
tune.kpV = [3.6, 2.4, 1.5]
tune.kiV = [0.54, 0.36]
else:
raise NotImplementedError('This longitudinal tune does not exist')
###### LAT ######
def set_lat_tune(tune, name, MAX_LAT_ACCEL=2.5, FRICTION=0.01, steering_angle_deadzone_deg=0.0, use_steering_angle=True):
if 'PID' in str(name):
tune.init('pid')
tune.pid.kiBP = [0.0]
tune.pid.kpBP = [0.0]
if name == LatTunes.PID_A:
tune.pid.kpV = [0.2]
tune.pid.kiV = [0.05]
tune.pid.kf = 0.00003
elif name == LatTunes.PID_C:
tune.pid.kpV = [0.6]
tune.pid.kiV = [0.1]
tune.pid.kf = 0.00006
elif name == LatTunes.PID_D:
tune.pid.kpV = [0.6]
tune.pid.kiV = [0.1]
tune.pid.kf = 0.00007818594
elif name == LatTunes.PID_F:
tune.pid.kpV = [0.723]
tune.pid.kiV = [0.0428]
tune.pid.kf = 0.00006
elif name == LatTunes.PID_G:
tune.pid.kpV = [0.18]
tune.pid.kiV = [0.015]
tune.pid.kf = 0.00012
elif name == LatTunes.PID_H:
tune.pid.kpV = [0.17]
tune.pid.kiV = [0.03]
tune.pid.kf = 0.00006
elif name == LatTunes.PID_I:
tune.pid.kpV = [0.15]
tune.pid.kiV = [0.05]
tune.pid.kf = 0.00004
elif name == LatTunes.PID_J:
tune.pid.kpV = [0.19]
tune.pid.kiV = [0.02]
tune.pid.kf = 0.00007818594
elif name == LatTunes.PID_L:
tune.pid.kpV = [0.3]
tune.pid.kiV = [0.05]
tune.pid.kf = 0.00006
elif name == LatTunes.PID_M:
tune.pid.kpV = [0.3]
tune.pid.kiV = [0.05]
tune.pid.kf = 0.00007
elif name == LatTunes.PID_N:
tune.pid.kpV = [0.35]
tune.pid.kiV = [0.15]
tune.pid.kf = 0.00007818594
else:
raise NotImplementedError('This PID tune does not exist')
else:
raise NotImplementedError('This lateral tune does not exist')

@ -555,6 +555,7 @@ FW_VERSIONS = {
b'\xf1\x8703N906026E \xf1\x892114', b'\xf1\x8703N906026E \xf1\x892114',
b'\xf1\x8704E906023AH\xf1\x893379', b'\xf1\x8704E906023AH\xf1\x893379',
b'\xf1\x8704L906026ET\xf1\x891990', b'\xf1\x8704L906026ET\xf1\x891990',
b'\xf1\x8704L906026FP\xf1\x892012',
b'\xf1\x8704L906026GA\xf1\x892013', b'\xf1\x8704L906026GA\xf1\x892013',
b'\xf1\x8704L906026KD\xf1\x894798', b'\xf1\x8704L906026KD\xf1\x894798',
b'\xf1\x873G0906264 \xf1\x890004', b'\xf1\x873G0906264 \xf1\x890004',
@ -562,6 +563,7 @@ FW_VERSIONS = {
(Ecu.transmission, 0x7e1, None): [ (Ecu.transmission, 0x7e1, None): [
b'\xf1\x870CW300043H \xf1\x891601', b'\xf1\x870CW300043H \xf1\x891601',
b'\xf1\x870CW300048R \xf1\x890610', b'\xf1\x870CW300048R \xf1\x890610',
b'\xf1\x870D9300013A \xf1\x894905',
b'\xf1\x870D9300014L \xf1\x895002', b'\xf1\x870D9300014L \xf1\x895002',
b'\xf1\x870D9300041A \xf1\x894801', b'\xf1\x870D9300041A \xf1\x894801',
b'\xf1\x870DD300045T \xf1\x891601', b'\xf1\x870DD300045T \xf1\x891601',
@ -579,6 +581,7 @@ FW_VERSIONS = {
], ],
(Ecu.eps, 0x712, None): [ (Ecu.eps, 0x712, None): [
b'\xf1\x873Q0909144J \xf1\x895063\xf1\x82\x0566B00611A1', b'\xf1\x873Q0909144J \xf1\x895063\xf1\x82\x0566B00611A1',
b'\xf1\x873Q0909144J \xf1\x895063\xf1\x82\x0566B00711A1',
b'\xf1\x875Q0909143M \xf1\x892041\xf1\x820522B0060803', b'\xf1\x875Q0909143M \xf1\x892041\xf1\x820522B0060803',
b'\xf1\x875Q0909143M \xf1\x892041\xf1\x820522B0080803', b'\xf1\x875Q0909143M \xf1\x892041\xf1\x820522B0080803',
b'\xf1\x875Q0909144AB\xf1\x891082\xf1\x82\00521B00606A1', b'\xf1\x875Q0909144AB\xf1\x891082\xf1\x82\00521B00606A1',

@ -82,45 +82,45 @@ class Controls:
self.log_sock = messaging.sub_sock('androidLog') self.log_sock = messaging.sub_sock('androidLog')
self.params = Params()
self.sm = sm
if self.sm is None:
ignore = ['testJoystick']
if SIMULATION:
ignore += ['driverCameraState', 'managerState']
if self.params.get_bool('WideCameraOnly'):
ignore += ['roadCameraState']
self.sm = messaging.SubMaster(['deviceState', 'pandaStates', 'peripheralState', 'modelV2', 'liveCalibration',
'driverMonitoringState', 'longitudinalPlan', 'lateralPlan', 'liveLocationKalman',
'managerState', 'liveParameters', 'radarState', 'liveTorqueParameters', 'testJoystick'] + self.camera_packets,
ignore_alive=ignore, ignore_avg_freq=['radarState', 'longitudinalPlan', 'testJoystick'])
if CI is None: if CI is None:
# wait for one pandaState and one CAN packet # wait for one pandaState and one CAN packet
print("Waiting for CAN messages...") print("Waiting for CAN messages...")
get_one_can(self.can_sock) get_one_can(self.can_sock)
self.CI, self.CP = get_car(self.can_sock, self.pm.sock['sendcan']) num_pandas = len(messaging.recv_one_retry(self.sm.sock['pandaStates']).pandaStates)
self.CI, self.CP = get_car(self.can_sock, self.pm.sock['sendcan'], num_pandas)
else: else:
self.CI, self.CP = CI, CI.CP self.CI, self.CP = CI, CI.CP
params = Params() self.joystick_mode = self.params.get_bool("JoystickDebugMode") or (self.CP.notCar and sm is None)
self.joystick_mode = params.get_bool("JoystickDebugMode") or (self.CP.notCar and sm is None)
joystick_packet = ['testJoystick'] if self.joystick_mode else []
self.sm = sm
if self.sm is None:
ignore = []
if SIMULATION:
ignore += ['driverCameraState', 'managerState']
if params.get_bool('WideCameraOnly'):
ignore += ['roadCameraState']
self.sm = messaging.SubMaster(['deviceState', 'pandaStates', 'peripheralState', 'modelV2', 'liveCalibration',
'driverMonitoringState', 'longitudinalPlan', 'lateralPlan', 'liveLocationKalman',
'managerState', 'liveParameters', 'radarState', 'liveTorqueParameters'] + self.camera_packets + joystick_packet,
ignore_alive=ignore, ignore_avg_freq=['radarState', 'longitudinalPlan'])
# set alternative experiences from parameters # set alternative experiences from parameters
self.disengage_on_accelerator = params.get_bool("DisengageOnAccelerator") self.disengage_on_accelerator = self.params.get_bool("DisengageOnAccelerator")
self.CP.alternativeExperience = 0 self.CP.alternativeExperience = 0
if not self.disengage_on_accelerator: if not self.disengage_on_accelerator:
self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.DISABLE_DISENGAGE_ON_GAS self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.DISABLE_DISENGAGE_ON_GAS
if self.CP.dashcamOnly and params.get_bool("DashcamOverride"): if self.CP.dashcamOnly and self.params.get_bool("DashcamOverride"):
self.CP.dashcamOnly = False self.CP.dashcamOnly = False
# read params # read params
self.is_metric = params.get_bool("IsMetric") self.is_metric = self.params.get_bool("IsMetric")
self.is_ldw_enabled = params.get_bool("IsLdwEnabled") self.is_ldw_enabled = self.params.get_bool("IsLdwEnabled")
openpilot_enabled_toggle = params.get_bool("OpenpilotEnabledToggle") openpilot_enabled_toggle = self.params.get_bool("OpenpilotEnabledToggle")
passive = params.get_bool("Passive") or not openpilot_enabled_toggle passive = self.params.get_bool("Passive") or not openpilot_enabled_toggle
# detect sound card presence and ensure successful init # detect sound card presence and ensure successful init
sounds_available = HARDWARE.get_sound_card_online() sounds_available = HARDWARE.get_sound_card_online()
@ -139,15 +139,15 @@ class Controls:
# Write CarParams for radard # Write CarParams for radard
cp_bytes = self.CP.to_bytes() cp_bytes = self.CP.to_bytes()
params.put("CarParams", cp_bytes) self.params.put("CarParams", cp_bytes)
put_nonblocking("CarParamsCache", cp_bytes) put_nonblocking("CarParamsCache", cp_bytes)
put_nonblocking("CarParamsPersistent", cp_bytes) put_nonblocking("CarParamsPersistent", cp_bytes)
# cleanup old params # cleanup old params
if not self.CP.experimentalLongitudinalAvailable: if not self.CP.experimentalLongitudinalAvailable:
params.remove("ExperimentalLongitudinalEnabled") self.params.remove("ExperimentalLongitudinalEnabled")
if not self.CP.openpilotLongitudinalControl: if not self.CP.openpilotLongitudinalControl:
params.remove("EndToEndLong") self.params.remove("EndToEndLong")
self.CC = car.CarControl.new_message() self.CC = car.CarControl.new_message()
self.CS_prev = car.CarState.new_message() self.CS_prev = car.CarState.new_message()
@ -583,9 +583,9 @@ class Controls:
"""Given the state, this function returns a CarControl packet""" """Given the state, this function returns a CarControl packet"""
# Update VehicleModel # Update VehicleModel
params = self.sm['liveParameters'] lp = self.sm['liveParameters']
x = max(params.stiffnessFactor, 0.1) x = max(lp.stiffnessFactor, 0.1)
sr = max(params.steerRatio, 0.1) sr = max(lp.steerRatio, 0.1)
self.VM.update_params(x, sr) self.VM.update_params(x, sr)
# Update Torque Params # Update Torque Params
@ -628,7 +628,7 @@ class Controls:
lat_plan.psis, lat_plan.psis,
lat_plan.curvatures, lat_plan.curvatures,
lat_plan.curvatureRates) lat_plan.curvatureRates)
actuators.steer, actuators.steeringAngleDeg, lac_log = self.LaC.update(CC.latActive, CS, self.VM, params, actuators.steer, actuators.steeringAngleDeg, lac_log = self.LaC.update(CC.latActive, CS, self.VM, lp,
self.last_actuators, self.steer_limited, self.desired_curvature, self.last_actuators, self.steer_limited, self.desired_curvature,
self.desired_curvature_rate, self.sm['liveLocationKalman']) self.desired_curvature_rate, self.sm['liveLocationKalman'])
else: else:
@ -768,10 +768,10 @@ class Controls:
(self.state == State.softDisabling) (self.state == State.softDisabling)
# Curvature & Steering angle # Curvature & Steering angle
params = self.sm['liveParameters'] lp = self.sm['liveParameters']
steer_angle_without_offset = math.radians(CS.steeringAngleDeg - params.angleOffsetDeg) steer_angle_without_offset = math.radians(CS.steeringAngleDeg - lp.angleOffsetDeg)
curvature = -self.VM.calc_curvature(steer_angle_without_offset, CS.vEgo, params.roll) curvature = -self.VM.calc_curvature(steer_angle_without_offset, CS.vEgo, lp.roll)
# controlsState # controlsState
dat = messaging.new_message('controlsState') dat = messaging.new_message('controlsState')
@ -856,6 +856,8 @@ class Controls:
start_time = sec_since_boot() start_time = sec_since_boot()
self.prof.checkpoint("Ratekeeper", ignore=True) self.prof.checkpoint("Ratekeeper", ignore=True)
self.is_metric = self.params.get_bool("IsMetric")
# Sample data from sockets and get a carState # Sample data from sockets and get a carState
CS = self.data_sample() CS = self.data_sample()
cloudlog.timestamp("Data sampled") cloudlog.timestamp("Data sampled")

@ -13,6 +13,7 @@ V_CRUISE_MIN = 8 # kph
V_CRUISE_ENABLE_MIN = 40 # kph V_CRUISE_ENABLE_MIN = 40 # kph
V_CRUISE_INITIAL = 255 # kph V_CRUISE_INITIAL = 255 # kph
MIN_SPEED = 1.0
LAT_MPC_N = 16 LAT_MPC_N = 16
LON_MPC_N = 32 LON_MPC_N = 32
CONTROL_N = 17 CONTROL_N = 17
@ -102,7 +103,7 @@ def get_lag_adjusted_curvature(CP, v_ego, psis, curvatures, curvature_rates):
psis = [0.0]*CONTROL_N psis = [0.0]*CONTROL_N
curvatures = [0.0]*CONTROL_N curvatures = [0.0]*CONTROL_N
curvature_rates = [0.0]*CONTROL_N curvature_rates = [0.0]*CONTROL_N
v_ego = max(v_ego, 0.1) v_ego = max(MIN_SPEED, v_ego)
# TODO this needs more thought, use .2s extra for now to estimate other delays # TODO this needs more thought, use .2s extra for now to estimate other delays
delay = CP.steerActuatorDelay + .2 delay = CP.steerActuatorDelay + .2

@ -811,7 +811,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, AlertCallbackType]]] = {
ET.NO_ENTRY: NoEntryAlert("Cruise Faulted"), ET.NO_ENTRY: NoEntryAlert("Cruise Faulted"),
}, },
EventName.gmAccFaultedTemp: { EventName.accFaultedTemp: {
ET.NO_ENTRY: NoEntryAlert("Cruise Temporarily Faulted"), ET.NO_ENTRY: NoEntryAlert("Cruise Temporarily Faulted"),
}, },

@ -17,7 +17,7 @@ from selfdrive.controls.lib.vehicle_model import ACCELERATION_DUE_TO_GRAVITY
# friction in the steering wheel that needs to be overcome to # friction in the steering wheel that needs to be overcome to
# move it at all, this is compensated for too. # move it at all, this is compensated for too.
LOW_SPEED_FACTOR = 100 LOW_SPEED_FACTOR = 200
class LatControlTorque(LatControl): class LatControlTorque(LatControl):

@ -4,7 +4,7 @@ from common.numpy_fast import interp
from system.swaglog import cloudlog from system.swaglog import cloudlog
from selfdrive.controls.lib.lateral_mpc_lib.lat_mpc import LateralMpc from selfdrive.controls.lib.lateral_mpc_lib.lat_mpc import LateralMpc
from selfdrive.controls.lib.lateral_mpc_lib.lat_mpc import N as LAT_MPC_N from selfdrive.controls.lib.lateral_mpc_lib.lat_mpc import N as LAT_MPC_N
from selfdrive.controls.lib.drive_helpers import CONTROL_N from selfdrive.controls.lib.drive_helpers import CONTROL_N, MIN_SPEED
from selfdrive.controls.lib.desire_helper import DesireHelper from selfdrive.controls.lib.desire_helper import DesireHelper
import cereal.messaging as messaging import cereal.messaging as messaging
from cereal import log from cereal import log
@ -23,8 +23,6 @@ LATERAL_JERK_COST = 0.05
# speed lateral control is stable on all cars # speed lateral control is stable on all cars
STEERING_RATE_COST = 800.0 STEERING_RATE_COST = 800.0
MIN_SPEED = .3
class LateralPlanner: class LateralPlanner:
def __init__(self, CP): def __init__(self, CP):

@ -253,7 +253,8 @@ class LongitudinalMpc:
cost_weights = [X_EGO_OBSTACLE_COST, X_EGO_COST, V_EGO_COST, A_EGO_COST, a_change_cost, J_EGO_COST] cost_weights = [X_EGO_OBSTACLE_COST, X_EGO_COST, V_EGO_COST, A_EGO_COST, a_change_cost, J_EGO_COST]
constraint_cost_weights = [LIMIT_COST, LIMIT_COST, LIMIT_COST, DANGER_ZONE_COST] constraint_cost_weights = [LIMIT_COST, LIMIT_COST, LIMIT_COST, DANGER_ZONE_COST]
elif self.mode == 'blended': elif self.mode == 'blended':
cost_weights = [0., 0.1, 0.2, 5.0, 0.0, 1.0] a_change_cost = 40.0 if prev_accel_constraint else 0
cost_weights = [0., 0.1, 0.2, 5.0, a_change_cost, 1.0]
constraint_cost_weights = [LIMIT_COST, LIMIT_COST, LIMIT_COST, 50.0] constraint_cost_weights = [LIMIT_COST, LIMIT_COST, LIMIT_COST, 50.0]
else: else:
raise NotImplementedError(f'Planner mode {self.mode} not recognized in planner cost set') raise NotImplementedError(f'Planner mode {self.mode} not recognized in planner cost set')

@ -133,7 +133,7 @@ class LongitudinalPlanner:
# TODO counter is only needed because radar is glitchy, remove once radar is gone # TODO counter is only needed because radar is glitchy, remove once radar is gone
# TODO write fcw in e2e_long mode # TODO write fcw in e2e_long mode
self.fcw = self.mpc.mode == 'acc' and self.mpc.crash_cnt > 5 self.fcw = self.mpc.mode == 'acc' and self.mpc.crash_cnt > 5 and not sm['carState'].standstill
if self.fcw: if self.fcw:
cloudlog.info("FCW triggered") cloudlog.info("FCW triggered")

@ -94,6 +94,9 @@ class TestStartup(unittest.TestCase):
time.sleep(2) # wait for controlsd to be ready time.sleep(2) # wait for controlsd to be ready
pm.send('can', can_list_to_can_capnp([[0, 0, b"", 0]]))
time.sleep(0.1)
msg = messaging.new_message('pandaStates', 1) msg = messaging.new_message('pandaStates', 1)
msg.pandaStates[0].pandaType = log.PandaState.PandaType.uno msg.pandaStates[0].pandaType = log.PandaState.PandaType.uno
pm.send('pandaStates', msg) pm.send('pandaStates', msg)

@ -54,6 +54,7 @@ def can_printer(bus=0, init_msgs=None, new_msgs=None, table=False):
update(new_msgs, bus, dat, low_to_high, high_to_low) update(new_msgs, bus, dat, low_to_high, high_to_low)
else: else:
# Live mode # Live mode
print(f"Waiting for messages on bus {bus}")
try: try:
while 1: while 1:
can_recv = messaging.drain_sock(logcan) can_recv = messaging.drain_sock(logcan)
@ -89,14 +90,17 @@ if __name__ == "__main__":
formatter_class=argparse.ArgumentDefaultsHelpFormatter) formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument("--bus", type=int, help="CAN bus to print out", default=0) parser.add_argument("--bus", type=int, help="CAN bus to print out", default=0)
parser.add_argument("--table", action="store_true", help="Print a cabana-like table") parser.add_argument("--table", action="store_true", help="Print a cabana-like table")
parser.add_argument("init", type=str, nargs='?', help="Route or segment to initialize with") parser.add_argument("init", type=str, nargs='?', help="Route or segment to initialize with. Use empty quotes to compare against all zeros.")
parser.add_argument("comp", type=str, nargs='?', help="Route or segment to compare against init") parser.add_argument("comp", type=str, nargs='?', help="Route or segment to compare against init")
args = parser.parse_args() args = parser.parse_args()
init_lr, new_lr = None, None init_lr, new_lr = None, None
if args.init: if args.init:
init_lr = logreader_from_route_or_segment(args.init) if args.init == '':
init_lr = []
else:
init_lr = logreader_from_route_or_segment(args.init)
if args.comp: if args.comp:
new_lr = logreader_from_route_or_segment(args.comp) new_lr = logreader_from_route_or_segment(args.comp)

@ -19,7 +19,7 @@ if __name__ == "__main__":
for m in msgs: for m in msgs:
ts[s].append(m.logMonoTime / 1e6) ts[s].append(m.logMonoTime / 1e6)
if len(ts[s]): if len(ts[s]) > 2:
d = np.diff(ts[s]) d = np.diff(ts[s])
print(f"{s:25} {np.mean(d):.2f} {np.std(d):.2f} {np.max(d):.2f} {np.min(d):.2f}") print(f"{s:25} {np.mean(d):.2f} {np.std(d):.2f} {np.max(d):.2f} {np.min(d):.2f}")
time.sleep(1) time.sleep(1)

@ -31,6 +31,7 @@ INPUTS_NEEDED = 5 # Minimum blocks needed for valid calibration
INPUTS_WANTED = 50 # We want a little bit more than we need for stability INPUTS_WANTED = 50 # We want a little bit more than we need for stability
MAX_ALLOWED_SPREAD = np.radians(2) MAX_ALLOWED_SPREAD = np.radians(2)
RPY_INIT = np.array([0.0,0.0,0.0]) RPY_INIT = np.array([0.0,0.0,0.0])
WIDE_FROM_DEVICE_EULER_INIT = np.array([0.0, 0.0, 0.0])
# These values are needed to accommodate biggest modelframe # These values are needed to accommodate biggest modelframe
PITCH_LIMITS = np.array([-0.09074112085129739, 0.14907572052989657]) PITCH_LIMITS = np.array([-0.09074112085129739, 0.14907572052989657])
@ -67,6 +68,7 @@ class Calibrator:
calibration_params = params.get("CalibrationParams") calibration_params = params.get("CalibrationParams")
self.wide_camera = params.get_bool('WideCameraOnly') self.wide_camera = params.get_bool('WideCameraOnly')
rpy_init = RPY_INIT rpy_init = RPY_INIT
wide_from_device_euler = WIDE_FROM_DEVICE_EULER_INIT
valid_blocks = 0 valid_blocks = 0
if param_put and calibration_params: if param_put and calibration_params:
@ -74,24 +76,34 @@ class Calibrator:
msg = log.Event.from_bytes(calibration_params) msg = log.Event.from_bytes(calibration_params)
rpy_init = np.array(msg.liveCalibration.rpyCalib) rpy_init = np.array(msg.liveCalibration.rpyCalib)
valid_blocks = msg.liveCalibration.validBlocks valid_blocks = msg.liveCalibration.validBlocks
wide_from_device_euler = np.array(msg.liveCalibration.wideFromDeviceEuler)
except Exception: except Exception:
cloudlog.exception("Error reading cached CalibrationParams") cloudlog.exception("Error reading cached CalibrationParams")
self.reset(rpy_init, valid_blocks) self.reset(rpy_init, valid_blocks, wide_from_device_euler)
self.update_status() self.update_status()
def reset(self, rpy_init: np.ndarray = RPY_INIT, valid_blocks: int = 0, smooth_from: Optional[np.ndarray] = None) -> None: def reset(self, rpy_init: np.ndarray = RPY_INIT,
valid_blocks: int = 0,
wide_from_device_euler_init: np.ndarray = WIDE_FROM_DEVICE_EULER_INIT,
smooth_from: Optional[np.ndarray] = None) -> None:
if not np.isfinite(rpy_init).all(): if not np.isfinite(rpy_init).all():
self.rpy = RPY_INIT.copy() self.rpy = RPY_INIT.copy()
else: else:
self.rpy = rpy_init.copy() self.rpy = rpy_init.copy()
if not np.isfinite(wide_from_device_euler_init).all() or len(wide_from_device_euler_init) != 3:
self.wide_from_device_euler = WIDE_FROM_DEVICE_EULER_INIT.copy()
else:
self.wide_from_device_euler = wide_from_device_euler_init.copy()
if not np.isfinite(valid_blocks) or valid_blocks < 0: if not np.isfinite(valid_blocks) or valid_blocks < 0:
self.valid_blocks = 0 self.valid_blocks = 0
else: else:
self.valid_blocks = valid_blocks self.valid_blocks = valid_blocks
self.rpys = np.tile(self.rpy, (INPUTS_WANTED, 1)) self.rpys = np.tile(self.rpy, (INPUTS_WANTED, 1))
self.wide_from_device_eulers = np.tile(self.wide_from_device_euler, (INPUTS_WANTED, 1))
self.idx = 0 self.idx = 0
self.block_idx = 0 self.block_idx = 0
@ -113,6 +125,7 @@ class Calibrator:
def update_status(self) -> None: def update_status(self) -> None:
valid_idxs = self.get_valid_idxs() valid_idxs = self.get_valid_idxs()
if valid_idxs: if valid_idxs:
self.wide_from_device_euler = np.mean(self.wide_from_device_eulers[valid_idxs], axis=0)
rpys = self.rpys[valid_idxs] rpys = self.rpys[valid_idxs]
self.rpy = np.mean(rpys, axis=0) self.rpy = np.mean(rpys, axis=0)
max_rpy_calib = np.array(np.max(rpys, axis=0)) max_rpy_calib = np.array(np.max(rpys, axis=0))
@ -146,7 +159,10 @@ class Calibrator:
else: else:
return self.rpy return self.rpy
def handle_cam_odom(self, trans: List[float], rot: List[float], trans_std: List[float]) -> Optional[np.ndarray]: def handle_cam_odom(self, trans: List[float],
rot: List[float],
wide_from_device_euler: List[float],
trans_std: List[float]) -> Optional[np.ndarray]:
self.old_rpy_weight = min(0.0, self.old_rpy_weight - 1/SMOOTH_CYCLES) self.old_rpy_weight = min(0.0, self.old_rpy_weight - 1/SMOOTH_CYCLES)
straight_and_fast = ((self.v_ego > MIN_SPEED_FILTER) and (trans[0] > MIN_SPEED_FILTER) and (abs(rot[2]) < MAX_YAW_RATE_FILTER)) straight_and_fast = ((self.v_ego > MIN_SPEED_FILTER) and (trans[0] > MIN_SPEED_FILTER) and (abs(rot[2]) < MAX_YAW_RATE_FILTER))
@ -165,7 +181,15 @@ class Calibrator:
new_rpy = euler_from_rot(rot_from_euler(self.get_smooth_rpy()).dot(rot_from_euler(observed_rpy))) new_rpy = euler_from_rot(rot_from_euler(self.get_smooth_rpy()).dot(rot_from_euler(observed_rpy)))
new_rpy = sanity_clip(new_rpy) new_rpy = sanity_clip(new_rpy)
self.rpys[self.block_idx] = (self.idx*self.rpys[self.block_idx] + (BLOCK_SIZE - self.idx) * new_rpy) / float(BLOCK_SIZE) if len(wide_from_device_euler) == 3:
new_wide_from_device_euler = np.array(wide_from_device_euler)
else:
new_wide_from_device_euler = WIDE_FROM_DEVICE_EULER_INIT
self.rpys[self.block_idx] = (self.idx*self.rpys[self.block_idx] +
(BLOCK_SIZE - self.idx) * new_rpy) / float(BLOCK_SIZE)
self.wide_from_device_eulers[self.block_idx] = (self.idx*self.wide_from_device_eulers[self.block_idx] +
(BLOCK_SIZE - self.idx) * new_wide_from_device_euler) / float(BLOCK_SIZE)
self.idx = (self.idx + 1) % BLOCK_SIZE self.idx = (self.idx + 1) % BLOCK_SIZE
if self.idx == 0: if self.idx == 0:
self.block_idx += 1 self.block_idx += 1
@ -187,6 +211,7 @@ class Calibrator:
liveCalibration.calPerc = min(100 * (self.valid_blocks * BLOCK_SIZE + self.idx) // (INPUTS_NEEDED * BLOCK_SIZE), 100) liveCalibration.calPerc = min(100 * (self.valid_blocks * BLOCK_SIZE + self.idx) // (INPUTS_NEEDED * BLOCK_SIZE), 100)
liveCalibration.rpyCalib = smooth_rpy.tolist() liveCalibration.rpyCalib = smooth_rpy.tolist()
liveCalibration.rpyCalibSpread = self.calib_spread.tolist() liveCalibration.rpyCalibSpread = self.calib_spread.tolist()
liveCalibration.wideFromDeviceEuler = self.wide_from_device_euler.tolist()
if self.not_car: if self.not_car:
liveCalibration.validBlocks = INPUTS_NEEDED liveCalibration.validBlocks = INPUTS_NEEDED
@ -223,6 +248,7 @@ def calibrationd_thread(sm: Optional[messaging.SubMaster] = None, pm: Optional[m
calibrator.handle_v_ego(sm['carState'].vEgo) calibrator.handle_v_ego(sm['carState'].vEgo)
new_rpy = calibrator.handle_cam_odom(sm['cameraOdometry'].trans, new_rpy = calibrator.handle_cam_odom(sm['cameraOdometry'].trans,
sm['cameraOdometry'].rot, sm['cameraOdometry'].rot,
sm['cameraOdometry'].wideFromDeviceEuler,
sm['cameraOdometry'].transStd) sm['cameraOdometry'].transStd)
if DEBUG and new_rpy is not None: if DEBUG and new_rpy is not None:

@ -55,7 +55,7 @@ int handle_encoder_msg(LoggerdState *s, Message *msg, std::string &name, struct
int bytes_count = 0; int bytes_count = 0;
// extract the message // extract the message
capnp::FlatArrayMessageReader cmsg(kj::ArrayPtr<capnp::word>((capnp::word *)msg->getData(), msg->getSize())); capnp::FlatArrayMessageReader cmsg(kj::ArrayPtr<capnp::word>((capnp::word *)msg->getData(), msg->getSize() / sizeof(capnp::word)));
auto event = cmsg.getRoot<cereal::Event>(); auto event = cmsg.getRoot<cereal::Event>();
auto edata = (name == "driverEncodeData") ? event.getDriverEncodeData() : auto edata = (name == "driverEncodeData") ? event.getDriverEncodeData() :
((name == "wideRoadEncodeData") ? event.getWideRoadEncodeData() : ((name == "wideRoadEncodeData") ? event.getWideRoadEncodeData() :

@ -83,6 +83,7 @@ if use_thneed and arch == "larch64" or GetOption('pc_thneed'):
"#tinygrad_repo/accel/opencl/ops_opencl.py", "#tinygrad_repo/accel/opencl/ops_opencl.py",
"#tinygrad_repo/accel/opencl/preprocessing.py", "#tinygrad_repo/accel/opencl/preprocessing.py",
"#tinygrad_repo/extra/onnx.py", "#tinygrad_repo/extra/onnx.py",
"#tinygrad_repo/extra/thneed.py",
"#tinygrad_repo/extra/utils.py", "#tinygrad_repo/extra/utils.py",
"#tinygrad_repo/tinygrad/llops/ops_gpu.py", "#tinygrad_repo/tinygrad/llops/ops_gpu.py",
"#tinygrad_repo/tinygrad/llops/ops_opencl.py", "#tinygrad_repo/tinygrad/llops/ops_opencl.py",

@ -1,2 +1,2 @@
ee8f830b-d6a1-42ef-9b1b-50fd0b2faae4 d1124586-761e-4e18-a771-6b5ef35124fe
cac8f7b69d420506707ff7a19d573d5011ef2533 6fec774f513a19e44d4316e46ad38277197d45ea

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:932e589e5cce66e5d9f48492426a33c74cd7f352a870d3ddafcede3e9156f30d oid sha256:517262fa9f1ad3cc8049ad3722903f40356d87ea423ee5cf011226fb6cfc3d5b
size 9157561 size 16072278

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:3587976a8b7e3be274fa86c2e2233e3e464cad713f5077c4394cd1ddd3c7c6c5 oid sha256:64b94659226a1e3c6594a13c2e5d029465d5803a5c3005121ec7217acdbbef20
size 2636965 size 4443461

@ -62,9 +62,9 @@ ModelOutput* model_eval_frame(ModelState* s, VisionBuf* buf, VisionBuf* wbuf,
// Model decides when action is completed // Model decides when action is completed
// so desire input is just a pulse triggered on rising edge // so desire input is just a pulse triggered on rising edge
if (desire_in[i] - s->prev_desire[i] > .99) { if (desire_in[i] - s->prev_desire[i] > .99) {
s->pulse_desire[DESIRE_LEN*(HISTORY_BUFFER_LEN-1)+i] = desire_in[i]; s->pulse_desire[DESIRE_LEN*HISTORY_BUFFER_LEN+i] = desire_in[i];
} else { } else {
s->pulse_desire[DESIRE_LEN*(HISTORY_BUFFER_LEN-1)+i] = 0.0; s->pulse_desire[DESIRE_LEN*HISTORY_BUFFER_LEN+i] = 0.0;
} }
s->prev_desire[i] = desire_in[i]; s->prev_desire[i] = desire_in[i];
} }
@ -363,14 +363,19 @@ void posenet_publish(PubMaster &pm, uint32_t vipc_frame_id, uint32_t vipc_droppe
MessageBuilder msg; MessageBuilder msg;
const auto &v_mean = net_outputs.pose.velocity_mean; const auto &v_mean = net_outputs.pose.velocity_mean;
const auto &r_mean = net_outputs.pose.rotation_mean; const auto &r_mean = net_outputs.pose.rotation_mean;
const auto &t_mean = net_outputs.wide_from_device_euler.mean;
const auto &v_std = net_outputs.pose.velocity_std; const auto &v_std = net_outputs.pose.velocity_std;
const auto &r_std = net_outputs.pose.rotation_std; const auto &r_std = net_outputs.pose.rotation_std;
const auto &t_std = net_outputs.wide_from_device_euler.std;
auto posenetd = msg.initEvent(valid && (vipc_dropped_frames < 1)).initCameraOdometry(); auto posenetd = msg.initEvent(valid && (vipc_dropped_frames < 1)).initCameraOdometry();
posenetd.setTrans({v_mean.x, v_mean.y, v_mean.z}); posenetd.setTrans({v_mean.x, v_mean.y, v_mean.z});
posenetd.setRot({r_mean.x, r_mean.y, r_mean.z}); posenetd.setRot({r_mean.x, r_mean.y, r_mean.z});
posenetd.setWideFromDeviceEuler({t_mean.x, t_mean.y, t_mean.z});
posenetd.setTransStd({exp(v_std.x), exp(v_std.y), exp(v_std.z)}); posenetd.setTransStd({exp(v_std.x), exp(v_std.y), exp(v_std.z)});
posenetd.setRotStd({exp(r_std.x), exp(r_std.y), exp(r_std.z)}); posenetd.setRotStd({exp(r_std.x), exp(r_std.y), exp(r_std.z)});
posenetd.setWideFromDeviceEulerStd({exp(t_std.x), exp(t_std.y), exp(t_std.z)});
posenetd.setTimestampEof(timestamp_eof); posenetd.setTimestampEof(timestamp_eof);
posenetd.setFrameId(vipc_frame_id); posenetd.setFrameId(vipc_frame_id);

@ -28,12 +28,13 @@ constexpr int BLINKER_LEN = 6;
constexpr int META_STRIDE = 7; constexpr int META_STRIDE = 7;
constexpr int PLAN_MHP_N = 5; constexpr int PLAN_MHP_N = 5;
constexpr int STOP_LINE_MHP_N = 3;
constexpr int LEAD_MHP_N = 2; constexpr int LEAD_MHP_N = 2;
constexpr int LEAD_TRAJ_LEN = 6; constexpr int LEAD_TRAJ_LEN = 6;
constexpr int LEAD_PRED_DIM = 4; constexpr int LEAD_PRED_DIM = 4;
constexpr int LEAD_MHP_SELECTION = 3; constexpr int LEAD_MHP_SELECTION = 3;
// Padding to get output shape as multiple of 4
constexpr int PAD_SIZE = 2;
struct ModelOutputXYZ { struct ModelOutputXYZ {
float x; float x;
@ -151,36 +152,6 @@ struct ModelOutputLeads {
}; };
static_assert(sizeof(ModelOutputLeads) == (sizeof(ModelOutputLeadPrediction)*LEAD_MHP_N) + (sizeof(float)*LEAD_MHP_SELECTION)); static_assert(sizeof(ModelOutputLeads) == (sizeof(ModelOutputLeadPrediction)*LEAD_MHP_N) + (sizeof(float)*LEAD_MHP_SELECTION));
struct ModelOutputStopLineElement {
ModelOutputXYZ position;
ModelOutputXYZ rotation;
float speed;
float time;
};
static_assert(sizeof(ModelOutputStopLineElement) == (sizeof(ModelOutputXYZ)*2 + sizeof(float)*2));
struct ModelOutputStopLinePrediction {
ModelOutputStopLineElement mean;
ModelOutputStopLineElement std;
float prob;
};
static_assert(sizeof(ModelOutputStopLinePrediction) == (sizeof(ModelOutputStopLineElement)*2 + sizeof(float)));
struct ModelOutputStopLines {
std::array<ModelOutputStopLinePrediction, STOP_LINE_MHP_N> prediction;
float prob;
constexpr const ModelOutputStopLinePrediction &get_best_prediction(int t_idx) const {
int max_idx = 0;
for (int i = 1; i < prediction.size(); i++) {
if (prediction[i].prob > prediction[max_idx].prob) {
max_idx = i;
}
}
return prediction[max_idx];
}
};
static_assert(sizeof(ModelOutputStopLines) == (sizeof(ModelOutputStopLinePrediction)*STOP_LINE_MHP_N) + sizeof(float));
struct ModelOutputPose { struct ModelOutputPose {
ModelOutputXYZ velocity_mean; ModelOutputXYZ velocity_mean;
@ -190,6 +161,12 @@ struct ModelOutputPose {
}; };
static_assert(sizeof(ModelOutputPose) == sizeof(ModelOutputXYZ)*4); static_assert(sizeof(ModelOutputPose) == sizeof(ModelOutputXYZ)*4);
struct ModelOutputWideFromDeviceEuler {
ModelOutputXYZ mean;
ModelOutputXYZ std;
};
static_assert(sizeof(ModelOutputWideFromDeviceEuler) == sizeof(ModelOutputXYZ)*2);
struct ModelOutputDisengageProb { struct ModelOutputDisengageProb {
float gas_disengage; float gas_disengage;
float brake_disengage; float brake_disengage;
@ -245,9 +222,9 @@ struct ModelOutput {
const ModelOutputLaneLines lane_lines; const ModelOutputLaneLines lane_lines;
const ModelOutputRoadEdges road_edges; const ModelOutputRoadEdges road_edges;
const ModelOutputLeads leads; const ModelOutputLeads leads;
const ModelOutputStopLines stop_lines;
const ModelOutputMeta meta; const ModelOutputMeta meta;
const ModelOutputPose pose; const ModelOutputPose pose;
const ModelOutputWideFromDeviceEuler wide_from_device_euler;
}; };
constexpr int OUTPUT_SIZE = sizeof(ModelOutput) / sizeof(float); constexpr int OUTPUT_SIZE = sizeof(ModelOutput) / sizeof(float);
@ -257,7 +234,7 @@ constexpr int OUTPUT_SIZE = sizeof(ModelOutput) / sizeof(float);
#else #else
constexpr int TEMPORAL_SIZE = 0; constexpr int TEMPORAL_SIZE = 0;
#endif #endif
constexpr int NET_OUTPUT_SIZE = OUTPUT_SIZE + FEATURE_LEN; constexpr int NET_OUTPUT_SIZE = OUTPUT_SIZE + FEATURE_LEN + PAD_SIZE;
// TODO: convert remaining arrays to std::array and update model runners // TODO: convert remaining arrays to std::array and update model runners
struct ModelState { struct ModelState {

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:022a830c39267f378f45204682060c93e3aa304bbd8cfa6b2dfe4fa8f419102d oid sha256:a41d42f92913e6cc3909e505b1220b16d31f7cfca5f8a4e82109577b4151b645
size 56972617 size 45922983

@ -29,10 +29,11 @@ class DRIVER_MONITOR_SETTINGS():
self._FACE_THRESHOLD = 0.7 self._FACE_THRESHOLD = 0.7
self._EYE_THRESHOLD = 0.65 self._EYE_THRESHOLD = 0.65
self._SG_THRESHOLD = 0.9 self._SG_THRESHOLD = 0.9
self._BLINK_THRESHOLD = 0.87 self._BLINK_THRESHOLD = 0.895
self._EE_THRESH11 = 0.75 self._EE_THRESH11 = 0.275
self._EE_THRESH12 = 3.25 self._EE_THRESH12 = 5.5
self._EE_MAX_OFFSET1 = 0.06
self._EE_THRESH21 = 0.01 self._EE_THRESH21 = 0.01
self._EE_THRESH22 = 0.35 self._EE_THRESH22 = 0.35
@ -204,14 +205,14 @@ class DriverStatus():
distracted_types.append(DistractedType.DISTRACTED_BLINK) distracted_types.append(DistractedType.DISTRACTED_BLINK)
if self.ee1_calibrated: if self.ee1_calibrated:
ee1_dist = self.eev1 > self.ee1_offseter.filtered_stat.M * self.settings._EE_THRESH12 ee1_dist = self.eev1 > min(self.ee1_offseter.filtered_stat.M, self.settings._EE_MAX_OFFSET1) * self.settings._EE_THRESH12
else: else:
ee1_dist = self.eev1 > self.settings._EE_THRESH11 ee1_dist = self.eev1 > self.settings._EE_THRESH11
if self.ee2_calibrated: # if self.ee2_calibrated:
ee2_dist = self.eev2 < self.ee2_offseter.filtered_stat.M * self.settings._EE_THRESH22 # ee2_dist = self.eev2 < self.ee2_offseter.filtered_stat.M * self.settings._EE_THRESH22
else: # else:
ee2_dist = self.eev2 < self.settings._EE_THRESH21 # ee2_dist = self.eev2 < self.settings._EE_THRESH21
if ee1_dist or ee2_dist: if ee1_dist:
distracted_types.append(DistractedType.DISTRACTED_E2E) distracted_types.append(DistractedType.DISTRACTED_E2E)
return distracted_types return distracted_types
@ -257,12 +258,11 @@ class DriverStatus():
self.pose.low_std = model_std_max < self.settings._POSESTD_THRESHOLD self.pose.low_std = model_std_max < self.settings._POSESTD_THRESHOLD
self.blink.left_blink = driver_data.leftBlinkProb * (driver_data.leftEyeProb > self.settings._EYE_THRESHOLD) * (driver_data.sunglassesProb < self.settings._SG_THRESHOLD) self.blink.left_blink = driver_data.leftBlinkProb * (driver_data.leftEyeProb > self.settings._EYE_THRESHOLD) * (driver_data.sunglassesProb < self.settings._SG_THRESHOLD)
self.blink.right_blink = driver_data.rightBlinkProb * (driver_data.rightEyeProb > self.settings._EYE_THRESHOLD) * (driver_data.sunglassesProb < self.settings._SG_THRESHOLD) self.blink.right_blink = driver_data.rightBlinkProb * (driver_data.rightEyeProb > self.settings._EYE_THRESHOLD) * (driver_data.sunglassesProb < self.settings._SG_THRESHOLD)
self.eev1 = driver_data.notReadyProb[1] self.eev1 = driver_data.notReadyProb[0]
self.eev2 = driver_data.readyProb[0] self.eev2 = driver_data.readyProb[0]
self.distracted_types = self._get_distracted_types() self.distracted_types = self._get_distracted_types()
self.driver_distracted = (DistractedType.DISTRACTED_POSE in self.distracted_types or self.driver_distracted = (DistractedType.DISTRACTED_E2E in self.distracted_types or DistractedType.DISTRACTED_POSE in self.distracted_types or DistractedType.DISTRACTED_BLINK in self.distracted_types) and \
DistractedType.DISTRACTED_BLINK in self.distracted_types) and \
driver_data.faceProb > self.settings._FACE_THRESHOLD and self.pose.low_std driver_data.faceProb > self.settings._FACE_THRESHOLD and self.pose.low_std
self.driver_distraction_filter.update(self.driver_distracted) self.driver_distraction_filter.update(self.driver_distracted)

@ -87,16 +87,24 @@ def try_setup_logs(diag, log_types):
else: else:
raise Exception(f"setup logs failed, {log_types=}") raise Exception(f"setup logs failed, {log_types=}")
def mmcli(cmd: str) -> None: def at_cmd(cmd: str) -> None:
for _ in range(5): for _ in range(5):
try: try:
subprocess.check_call(f"mmcli -m any --timeout 30 {cmd}", shell=True) subprocess.check_call(f"mmcli -m any --timeout 30 --command='{cmd}'", shell=True)
break break
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
cloudlog.exception("rawgps.mmcli_command_failed") cloudlog.exception("rawgps.mmcli_command_failed")
else: else:
raise Exception(f"failed to execute mmcli command {cmd=}") raise Exception(f"failed to execute mmcli command {cmd=}")
def gps_enabled() -> bool:
try:
p = subprocess.check_output("mmcli -m any --command=\"AT+QGPS?\"", shell=True)
return b"QGPS: 1" in p
except subprocess.CalledProcessError as exc:
raise Exception("failed to execute QGPS mmcli command") from exc
def setup_quectel(diag: ModemDiag): def setup_quectel(diag: ModemDiag):
# enable OEMDRE in the NV # enable OEMDRE in the NV
# TODO: it has to reboot for this to take effect # TODO: it has to reboot for this to take effect
@ -108,11 +116,16 @@ def setup_quectel(diag: ModemDiag):
setup_logs(diag, LOG_TYPES) setup_logs(diag, LOG_TYPES)
if gps_enabled():
at_cmd("AT+QGPSEND")
# disable DPO power savings for more accuracy # disable DPO power savings for more accuracy
mmcli("--command='AT+QGPSCFG=\"dpoenable\",0'") at_cmd("AT+QGPSCFG=\"dpoenable\",0")
# don't automatically turn on GNSS on powerup # don't automatically turn on GNSS on powerup
mmcli("--command='AT+QGPSCFG=\"autogps\",0'") at_cmd("AT+QGPSCFG=\"autogps\",0")
mmcli("--location-enable-gps-raw --location-enable-gps-nmea")
at_cmd("AT+QGPSCFG=\"outport\",\"usbnmea\"")
at_cmd("AT+QGPS=1")
# enable OEMDRE mode # enable OEMDRE mode
DIAG_SUBSYS_CMD_F = 75 DIAG_SUBSYS_CMD_F = 75
@ -134,7 +147,9 @@ def setup_quectel(diag: ModemDiag):
)) ))
def teardown_quectel(diag): def teardown_quectel(diag):
mmcli("--location-disable-gps-raw --location-disable-gps-nmea") at_cmd("AT+QGPSCFG=\"outport\",\"none\"")
if gps_enabled():
at_cmd("AT+QGPSEND")
try_setup_logs(diag, []) try_setup_logs(diag, [])
@ -156,7 +171,7 @@ def main() -> NoReturn:
# wait for ModemManager to come up # wait for ModemManager to come up
cloudlog.warning("waiting for modem to come up") cloudlog.warning("waiting for modem to come up")
while True: while True:
ret = subprocess.call("mmcli -m any --timeout 10 --location-status", stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, shell=True) ret = subprocess.call("mmcli -m any --timeout 10 --command=\"AT+QGPS?\"", stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, shell=True)
if ret == 0: if ret == 0:
break break
time.sleep(0.1) time.sleep(0.1)

@ -22,7 +22,7 @@ from tools.lib.logreader import LogReader
TEST_ROUTE = "4cf7a6ad03080c90|2021-09-29--13-46-36" TEST_ROUTE = "4cf7a6ad03080c90|2021-09-29--13-46-36"
SEGMENT = 0 SEGMENT = 0
MAX_FRAMES = 100 if PC else 1300 MAX_FRAMES = 100 if PC else 600
SEND_EXTRA_INPUTS = bool(os.getenv("SEND_EXTRA_INPUTS", "0")) SEND_EXTRA_INPUTS = bool(os.getenv("SEND_EXTRA_INPUTS", "0"))
@ -149,9 +149,9 @@ if __name__ == "__main__":
# load logs # load logs
lr = list(LogReader(get_url(TEST_ROUTE, SEGMENT))) lr = list(LogReader(get_url(TEST_ROUTE, SEGMENT)))
frs = { frs = {
'roadCameraState': FrameReader(get_url(TEST_ROUTE, SEGMENT, log_type="fcamera")), 'roadCameraState': FrameReader(get_url(TEST_ROUTE, SEGMENT, log_type="fcamera"), readahead=True),
'driverCameraState': FrameReader(get_url(TEST_ROUTE, SEGMENT, log_type="dcamera")), 'driverCameraState': FrameReader(get_url(TEST_ROUTE, SEGMENT, log_type="dcamera"), readahead=True),
'wideRoadCameraState': FrameReader(get_url(TEST_ROUTE, SEGMENT, log_type="ecamera")) 'wideRoadCameraState': FrameReader(get_url(TEST_ROUTE, SEGMENT, log_type="ecamera"), readahead=True)
} }
# run replay # run replay

@ -1 +1 @@
bfb0a2a52212d2aa1619d999aaae97fa7f7ff788 d2f1711fd58d4f2c25b81bd332270da60ff9636d

@ -1 +1 @@
e5a86c14e2318f2dd218b3985cdbea6f875f7d83 8f2919ba4d8509432e93ff0a44f951254c1ff3fe

@ -18,7 +18,7 @@ from tools.lib.logreader import LogReader
source_segments = [ source_segments = [
("BODY", "937ccb7243511b65|2022-05-24--16-03-09--1"), # COMMA.BODY ("BODY", "937ccb7243511b65|2022-05-24--16-03-09--1"), # COMMA.BODY
("HYUNDAI", "02c45f73a2e5c6e9|2021-01-01--19-08-22--1"), # HYUNDAI.SONATA ("HYUNDAI", "02c45f73a2e5c6e9|2021-01-01--19-08-22--1"), # HYUNDAI.SONATA
("HYUNDAI2", "d824e27e8c60172c|2022-09-13--11-26-50--2"), # HYUNDAI.KIA_EV6 ("HYUNDAI2", "d545129f3ca90f28|2022-10-19--09-22-54--9"), # HYUNDAI.KIA_EV6
("TOYOTA", "0982d79ebb0de295|2021-01-04--17-13-21--13"), # TOYOTA.PRIUS (INDI) ("TOYOTA", "0982d79ebb0de295|2021-01-04--17-13-21--13"), # TOYOTA.PRIUS (INDI)
("TOYOTA2", "0982d79ebb0de295|2021-01-03--20-03-36--6"), # TOYOTA.RAV4 (LQR) ("TOYOTA2", "0982d79ebb0de295|2021-01-03--20-03-36--6"), # TOYOTA.RAV4 (LQR)
("TOYOTA3", "f7d7e3538cda1a2a|2021-08-16--08-55-34--6"), # TOYOTA.COROLLA_TSS2 ("TOYOTA3", "f7d7e3538cda1a2a|2021-08-16--08-55-34--6"), # TOYOTA.COROLLA_TSS2
@ -40,7 +40,7 @@ source_segments = [
segments = [ segments = [
("BODY", "regenFA002A80700|2022-09-27--15-37-02--0"), ("BODY", "regenFA002A80700|2022-09-27--15-37-02--0"),
("HYUNDAI", "regenBE53A59065B|2022-09-27--16-52-03--0"), ("HYUNDAI", "regenBE53A59065B|2022-09-27--16-52-03--0"),
("HYUNDAI2", "regenFA8B5CA9840|2022-10-12--21-47-06--0"), ("HYUNDAI2", "d545129f3ca90f28|2022-10-19--09-22-54--9"),
("TOYOTA", "regen929C5790007|2022-09-27--16-27-47--0"), ("TOYOTA", "regen929C5790007|2022-09-27--16-27-47--0"),
("TOYOTA2", "regenEA3950D7F22|2022-09-27--15-43-24--0"), ("TOYOTA2", "regenEA3950D7F22|2022-09-27--15-43-24--0"),
("TOYOTA3", "regen89026F6BD8D|2022-09-27--15-45-37--0"), ("TOYOTA3", "regen89026F6BD8D|2022-09-27--15-45-37--0"),

@ -60,6 +60,7 @@ find . -maxdepth 1 -not -path './.git' -not -name '.' -not -name '..' -exec rm -
git reset --hard $GIT_COMMIT git reset --hard $GIT_COMMIT
git checkout $GIT_COMMIT git checkout $GIT_COMMIT
git clean -xdff git clean -xdff
git submodule sync
git submodule update --init --recursive git submodule update --init --recursive
git submodule foreach --recursive "git reset --hard && git clean -xdff" git submodule foreach --recursive "git reset --hard && git clean -xdff"

@ -120,8 +120,8 @@ class TestOnroad(unittest.TestCase):
if "DEBUG" in os.environ: if "DEBUG" in os.environ:
segs = filter(lambda x: os.path.exists(os.path.join(x, "rlog")), Path(ROOT).iterdir()) segs = filter(lambda x: os.path.exists(os.path.join(x, "rlog")), Path(ROOT).iterdir())
segs = sorted(segs, key=lambda x: x.stat().st_mtime) segs = sorted(segs, key=lambda x: x.stat().st_mtime)
print(segs[-1]) print(segs[-2])
cls.lr = list(LogReader(os.path.join(segs[-1], "rlog"))) cls.lr = list(LogReader(os.path.join(segs[-2], "rlog")))
return return
# setup env # setup env
@ -187,6 +187,25 @@ class TestOnroad(unittest.TestCase):
big_logs = [f for f, n in cnt.most_common(3) if n / sum(cnt.values()) > 30.] big_logs = [f for f, n in cnt.most_common(3) if n / sum(cnt.values()) > 30.]
self.assertEqual(len(big_logs), 0, f"Log spam: {big_logs}") self.assertEqual(len(big_logs), 0, f"Log spam: {big_logs}")
def test_ui_timings(self):
result = "\n"
result += "------------------------------------------------\n"
result += "-------------- UI Draw Timing ------------------\n"
result += "------------------------------------------------\n"
ts = [m.uiDebug.drawTimeMillis for m in self.lr if m.which() == 'uiDebug']
result += f"min {min(ts):.2f}ms\n"
result += f"max {max(ts):.2f}ms\n"
result += f"std {np.std(ts):.2f}ms\n"
result += f"mean {np.mean(ts):.2f}ms\n"
result += "------------------------------------------------\n"
print(result)
self.assertGreater(len(ts), 20*50, "insufficient samples")
self.assertLess(max(ts), 30.)
self.assertLess(np.mean(ts), 10.)
self.assertLess(np.std(ts), 5.)
def test_cpu_usage(self): def test_cpu_usage(self):
proclogs = [m for m in self.lr if m.which() == 'procLog'] proclogs = [m for m in self.lr if m.which() == 'procLog']
self.assertGreater(len(proclogs), service_list['procLog'].frequency * 45, "insufficient samples") self.assertGreater(len(proclogs), service_list['procLog'].frequency * 45, "insufficient samples")

@ -1,6 +1,8 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from functools import lru_cache
import sys import sys
import subprocess import subprocess
from tqdm import tqdm
from azure.storage.blob import BlockBlobService # pylint: disable=import-error from azure.storage.blob import BlockBlobService # pylint: disable=import-error
from selfdrive.car.tests.routes import routes as test_car_models_routes from selfdrive.car.tests.routes import routes as test_car_models_routes
@ -10,11 +12,11 @@ from xx.chffr.lib.storage import _DATA_ACCOUNT_PRODUCTION, _DATA_ACCOUNT_CI, _DA
SOURCES = [ SOURCES = [
(_DATA_ACCOUNT_PRODUCTION, _DATA_BUCKET_PRODUCTION), (_DATA_ACCOUNT_PRODUCTION, _DATA_BUCKET_PRODUCTION),
(_DATA_ACCOUNT_PRODUCTION, "preserve"),
(_DATA_ACCOUNT_CI, "commadataci"), (_DATA_ACCOUNT_CI, "commadataci"),
] ]
@lru_cache
def get_azure_keys(): def get_azure_keys():
dest_key = azureutil.get_user_token(_DATA_ACCOUNT_CI, "openpilotci") dest_key = azureutil.get_user_token(_DATA_ACCOUNT_CI, "openpilotci")
source_keys = [azureutil.get_user_token(account, bucket) for account, bucket in SOURCES] source_keys = [azureutil.get_user_token(account, bucket) for account, bucket in SOURCES]
@ -82,7 +84,7 @@ if __name__ == "__main__":
to_sync.extend([rt.route for rt in test_car_models_routes]) to_sync.extend([rt.route for rt in test_car_models_routes])
to_sync.extend([s[1].rsplit('--', 1)[0] for s in replay_segments]) to_sync.extend([s[1].rsplit('--', 1)[0] for s in replay_segments])
for r in to_sync: for r in tqdm(to_sync):
if not sync_to_ci_public(r): if not sync_to_ci_public(r):
failed_routes.append(r) failed_routes.append(r)

@ -1,11 +1,9 @@
#include "selfdrive/ui/qt/home.h" #include "selfdrive/ui/qt/home.h"
#include <QDateTime>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QMouseEvent> #include <QMouseEvent>
#include <QVBoxLayout> #include <QVBoxLayout>
#include "common/params.h"
#include "selfdrive/ui/qt/util.h" #include "selfdrive/ui/qt/util.h"
#include "selfdrive/ui/qt/widgets/drive_stats.h" #include "selfdrive/ui/qt/widgets/drive_stats.h"
#include "selfdrive/ui/qt/widgets/prime.h" #include "selfdrive/ui/qt/widgets/prime.h"
@ -109,22 +107,20 @@ OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) {
header_layout->setContentsMargins(15, 15, 15, 0); header_layout->setContentsMargins(15, 15, 15, 0);
header_layout->setSpacing(16); header_layout->setSpacing(16);
date = new QLabel();
header_layout->addWidget(date, 1, Qt::AlignHCenter | Qt::AlignLeft);
update_notif = new QPushButton(tr("UPDATE")); update_notif = new QPushButton(tr("UPDATE"));
update_notif->setVisible(false); update_notif->setVisible(false);
update_notif->setStyleSheet("background-color: #364DEF;"); update_notif->setStyleSheet("background-color: #364DEF;");
QObject::connect(update_notif, &QPushButton::clicked, [=]() { center_layout->setCurrentIndex(1); }); QObject::connect(update_notif, &QPushButton::clicked, [=]() { center_layout->setCurrentIndex(1); });
header_layout->addWidget(update_notif, 0, Qt::AlignHCenter | Qt::AlignRight); header_layout->addWidget(update_notif, 0, Qt::AlignHCenter | Qt::AlignLeft);
alert_notif = new QPushButton(); alert_notif = new QPushButton();
alert_notif->setVisible(false); alert_notif->setVisible(false);
alert_notif->setStyleSheet("background-color: #E22C2C;"); alert_notif->setStyleSheet("background-color: #E22C2C;");
QObject::connect(alert_notif, &QPushButton::clicked, [=] { center_layout->setCurrentIndex(2); }); QObject::connect(alert_notif, &QPushButton::clicked, [=] { center_layout->setCurrentIndex(2); });
header_layout->addWidget(alert_notif, 0, Qt::AlignHCenter | Qt::AlignRight); header_layout->addWidget(alert_notif, 0, Qt::AlignHCenter | Qt::AlignLeft);
header_layout->addWidget(new QLabel(getBrandVersion()), 0, Qt::AlignHCenter | Qt::AlignRight); version = new ElidedLabel();
header_layout->addWidget(version, 0, Qt::AlignHCenter | Qt::AlignRight);
main_layout->addLayout(header_layout); main_layout->addLayout(header_layout);
@ -184,9 +180,7 @@ void OffroadHome::hideEvent(QHideEvent *event) {
} }
void OffroadHome::refresh() { void OffroadHome::refresh() {
QString locale_name = QString(uiState()->language).replace("main_", ""); version->setText(getBrand() + " " + QString::fromStdString(params.get("UpdaterCurrentDescription")));
QString dateString = QLocale(locale_name).toString(QDateTime::currentDateTime(), "dddd, MMMM d");
date->setText(dateString);
bool updateAvailable = update_widget->refresh(); bool updateAvailable = update_widget->refresh();
int alerts = alerts_widget->refresh(); int alerts = alerts_widget->refresh();

@ -7,10 +7,12 @@
#include <QTimer> #include <QTimer>
#include <QWidget> #include <QWidget>
#include "common/params.h"
#include "selfdrive/ui/qt/offroad/driverview.h" #include "selfdrive/ui/qt/offroad/driverview.h"
#include "selfdrive/ui/qt/body.h" #include "selfdrive/ui/qt/body.h"
#include "selfdrive/ui/qt/onroad.h" #include "selfdrive/ui/qt/onroad.h"
#include "selfdrive/ui/qt/sidebar.h" #include "selfdrive/ui/qt/sidebar.h"
#include "selfdrive/ui/qt/widgets/controls.h"
#include "selfdrive/ui/qt/widgets/offroad_alerts.h" #include "selfdrive/ui/qt/widgets/offroad_alerts.h"
#include "selfdrive/ui/ui.h" #include "selfdrive/ui/ui.h"
@ -25,8 +27,10 @@ private:
void hideEvent(QHideEvent *event) override; void hideEvent(QHideEvent *event) override;
void refresh(); void refresh();
Params params;
QTimer* timer; QTimer* timer;
QLabel* date; ElidedLabel* version;
QStackedLayout* center_layout; QStackedLayout* center_layout;
UpdateAlert *update_widget; UpdateAlert *update_widget;
OffroadAlert* alerts_widget; OffroadAlert* alerts_widget;

@ -12,11 +12,11 @@ DriverViewWindow::DriverViewWindow(QWidget* parent) : QWidget(parent) {
layout = new QStackedLayout(this); layout = new QStackedLayout(this);
layout->setStackingMode(QStackedLayout::StackAll); layout->setStackingMode(QStackedLayout::StackAll);
cameraView = new CameraViewWidget("camerad", VISION_STREAM_DRIVER, true, this); cameraView = new CameraWidget("camerad", VISION_STREAM_DRIVER, true, this);
layout->addWidget(cameraView); layout->addWidget(cameraView);
scene = new DriverViewScene(this); scene = new DriverViewScene(this);
connect(cameraView, &CameraViewWidget::vipcThreadFrameReceived, scene, &DriverViewScene::frameUpdated); connect(cameraView, &CameraWidget::vipcThreadFrameReceived, scene, &DriverViewScene::frameUpdated);
layout->addWidget(scene); layout->addWidget(scene);
layout->setCurrentWidget(scene); layout->setCurrentWidget(scene);
} }

@ -42,7 +42,7 @@ protected:
void mouseReleaseEvent(QMouseEvent* e) override; void mouseReleaseEvent(QMouseEvent* e) override;
private: private:
CameraViewWidget *cameraView; CameraWidget *cameraView;
DriverViewScene *scene; DriverViewScene *scene;
QStackedLayout *layout; QStackedLayout *layout;
}; };

@ -145,11 +145,11 @@ void SoftwarePanel::updateLabels() {
targetBranchBtn->setValue(QString::fromStdString(params.get("UpdaterTargetBranch"))); targetBranchBtn->setValue(QString::fromStdString(params.get("UpdaterTargetBranch")));
// current + new versions // current + new versions
versionLbl->setText(QString::fromStdString(params.get("UpdaterCurrentDescription")).left(40)); versionLbl->setText(QString::fromStdString(params.get("UpdaterCurrentDescription")));
versionLbl->setDescription(QString::fromStdString(params.get("UpdaterCurrentReleaseNotes"))); versionLbl->setDescription(QString::fromStdString(params.get("UpdaterCurrentReleaseNotes")));
installBtn->setVisible(!is_onroad && params.getBool("UpdateAvailable")); installBtn->setVisible(!is_onroad && params.getBool("UpdateAvailable"));
installBtn->setValue(QString::fromStdString(params.get("UpdaterNewDescription")).left(35)); installBtn->setValue(QString::fromStdString(params.get("UpdaterNewDescription")));
installBtn->setDescription(QString::fromStdString(params.get("UpdaterNewReleaseNotes"))); installBtn->setDescription(QString::fromStdString(params.get("UpdaterNewReleaseNotes")));
update(); update();

@ -368,7 +368,7 @@ void WifiManager::updateGsmSettings(bool roaming, QString apn, bool metered) {
changes = true; changes = true;
} }
int meteredInt = metered ? NM_METERED_NO : NM_METERED_UNKNOWN; int meteredInt = metered ? NM_METERED_UNKNOWN : NM_METERED_NO;
if (settings.value("connection").value("metered").toInt() != meteredInt) { if (settings.value("connection").value("metered").toInt() != meteredInt) {
qWarning() << "Changing connection.metered to" << meteredInt; qWarning() << "Changing connection.metered to" << meteredInt;
settings["connection"]["metered"] = meteredInt; settings["connection"]["metered"] = meteredInt;

@ -18,7 +18,7 @@ OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent) {
stacked_layout->setStackingMode(QStackedLayout::StackAll); stacked_layout->setStackingMode(QStackedLayout::StackAll);
main_layout->addLayout(stacked_layout); main_layout->addLayout(stacked_layout);
nvg = new NvgWindow(VISION_STREAM_ROAD, this); nvg = new AnnotatedCameraWidget(VISION_STREAM_ROAD, this);
QWidget * split_wrapper = new QWidget; QWidget * split_wrapper = new QWidget;
split = new QHBoxLayout(split_wrapper); split = new QHBoxLayout(split_wrapper);
@ -27,7 +27,7 @@ OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent) {
split->addWidget(nvg); split->addWidget(nvg);
if (getenv("DUAL_CAMERA_VIEW")) { if (getenv("DUAL_CAMERA_VIEW")) {
CameraViewWidget *arCam = new CameraViewWidget("camerad", VISION_STREAM_ROAD, true, this); CameraWidget *arCam = new CameraWidget("camerad", VISION_STREAM_ROAD, true, this);
split->insertWidget(0, arCam); split->insertWidget(0, arCam);
} }
@ -173,14 +173,15 @@ void OnroadAlerts::paintEvent(QPaintEvent *event) {
} }
} }
// NvgWindow
NvgWindow::NvgWindow(VisionStreamType type, QWidget* parent) : fps_filter(UI_FREQ, 3, 1. / UI_FREQ), CameraViewWidget("camerad", type, true, parent) { AnnotatedCameraWidget::AnnotatedCameraWidget(VisionStreamType type, QWidget* parent) : fps_filter(UI_FREQ, 3, 1. / UI_FREQ), CameraWidget("camerad", type, true, parent) {
pm = std::make_unique<PubMaster, const std::initializer_list<const char *>>({"uiDebug"});
engage_img = loadPixmap("../assets/img_chffr_wheel.png", {img_size, img_size}); engage_img = loadPixmap("../assets/img_chffr_wheel.png", {img_size, img_size});
dm_img = loadPixmap("../assets/img_driver_face.png", {img_size, img_size}); dm_img = loadPixmap("../assets/img_driver_face.png", {img_size, img_size});
} }
void NvgWindow::updateState(const UIState &s) { void AnnotatedCameraWidget::updateState(const UIState &s) {
const int SET_SPEED_NA = 255; const int SET_SPEED_NA = 255;
const SubMaster &sm = *(s.sm); const SubMaster &sm = *(s.sm);
@ -232,13 +233,13 @@ void NvgWindow::updateState(const UIState &s) {
} }
if (s.scene.calibration_valid) { if (s.scene.calibration_valid) {
CameraViewWidget::updateCalibration(s.scene.view_from_calib); CameraWidget::updateCalibration(s.scene.view_from_calib);
} else { } else {
CameraViewWidget::updateCalibration(DEFAULT_CALIBRATION); CameraWidget::updateCalibration(DEFAULT_CALIBRATION);
} }
} }
void NvgWindow::drawHud(QPainter &p) { void AnnotatedCameraWidget::drawHud(QPainter &p) {
p.save(); p.save();
// Header gradient // Header gradient
@ -400,7 +401,11 @@ void NvgWindow::drawHud(QPainter &p) {
p.restore(); p.restore();
} }
void NvgWindow::drawText(QPainter &p, int x, int y, const QString &text, int alpha) {
// Window that shows camera view and variety of
// info drawn on top
void AnnotatedCameraWidget::drawText(QPainter &p, int x, int y, const QString &text, int alpha) {
QRect real_rect = getTextRect(p, 0, text); QRect real_rect = getTextRect(p, 0, text);
real_rect.moveCenter({x, y - real_rect.height() / 2}); real_rect.moveCenter({x, y - real_rect.height() / 2});
@ -408,7 +413,7 @@ void NvgWindow::drawText(QPainter &p, int x, int y, const QString &text, int alp
p.drawText(real_rect.x(), real_rect.bottom(), text); p.drawText(real_rect.x(), real_rect.bottom(), text);
} }
void NvgWindow::drawIcon(QPainter &p, int x, int y, QPixmap &img, QBrush bg, float opacity) { void AnnotatedCameraWidget::drawIcon(QPainter &p, int x, int y, QPixmap &img, QBrush bg, float opacity) {
p.setPen(Qt::NoPen); p.setPen(Qt::NoPen);
p.setBrush(bg); p.setBrush(bg);
p.drawEllipse(x - radius / 2, y - radius / 2, radius, radius); p.drawEllipse(x - radius / 2, y - radius / 2, radius, radius);
@ -417,8 +422,8 @@ void NvgWindow::drawIcon(QPainter &p, int x, int y, QPixmap &img, QBrush bg, flo
} }
void NvgWindow::initializeGL() { void AnnotatedCameraWidget::initializeGL() {
CameraViewWidget::initializeGL(); CameraWidget::initializeGL();
qInfo() << "OpenGL version:" << QString((const char*)glGetString(GL_VERSION)); qInfo() << "OpenGL version:" << QString((const char*)glGetString(GL_VERSION));
qInfo() << "OpenGL vendor:" << QString((const char*)glGetString(GL_VENDOR)); qInfo() << "OpenGL vendor:" << QString((const char*)glGetString(GL_VENDOR));
qInfo() << "OpenGL renderer:" << QString((const char*)glGetString(GL_RENDERER)); qInfo() << "OpenGL renderer:" << QString((const char*)glGetString(GL_RENDERER));
@ -428,8 +433,8 @@ void NvgWindow::initializeGL() {
setBackgroundColor(bg_colors[STATUS_DISENGAGED]); setBackgroundColor(bg_colors[STATUS_DISENGAGED]);
} }
void NvgWindow::updateFrameMat() { void AnnotatedCameraWidget::updateFrameMat() {
CameraViewWidget::updateFrameMat(); CameraWidget::updateFrameMat();
UIState *s = uiState(); UIState *s = uiState();
int w = width(), h = height(); int w = width(), h = height();
@ -446,7 +451,7 @@ void NvgWindow::updateFrameMat() {
.translate(-intrinsic_matrix.v[2], -intrinsic_matrix.v[5]); .translate(-intrinsic_matrix.v[2], -intrinsic_matrix.v[5]);
} }
void NvgWindow::drawLaneLines(QPainter &painter, const UIState *s) { void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s) {
painter.save(); painter.save();
const UIScene &scene = s->scene; const UIScene &scene = s->scene;
@ -505,7 +510,7 @@ void NvgWindow::drawLaneLines(QPainter &painter, const UIState *s) {
painter.restore(); painter.restore();
} }
void NvgWindow::drawLead(QPainter &painter, const cereal::ModelDataV2::LeadDataV3::Reader &lead_data, const QPointF &vd) { void AnnotatedCameraWidget::drawLead(QPainter &painter, const cereal::ModelDataV2::LeadDataV3::Reader &lead_data, const QPointF &vd) {
painter.save(); painter.save();
const float speedBuff = 10.; const float speedBuff = 10.;
@ -541,11 +546,13 @@ void NvgWindow::drawLead(QPainter &painter, const cereal::ModelDataV2::LeadDataV
painter.restore(); painter.restore();
} }
void NvgWindow::paintGL() { void AnnotatedCameraWidget::paintGL() {
const double start_draw_t = millis_since_boot();
UIState *s = uiState(); UIState *s = uiState();
const cereal::ModelDataV2::Reader &model = (*s->sm)["modelV2"].getModelV2(); const cereal::ModelDataV2::Reader &model = (*s->sm)["modelV2"].getModelV2();
CameraViewWidget::setFrameId(model.getFrameId()); CameraWidget::setFrameId(model.getFrameId());
CameraViewWidget::paintGL(); CameraWidget::paintGL();
QPainter painter(this); QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::Antialiasing);
@ -575,10 +582,16 @@ void NvgWindow::paintGL() {
LOGW("slow frame rate: %.2f fps", fps); LOGW("slow frame rate: %.2f fps", fps);
} }
prev_draw_t = cur_draw_t; prev_draw_t = cur_draw_t;
// publish debug msg
MessageBuilder msg;
auto m = msg.initEvent().initUiDebug();
m.setDrawTimeMillis(cur_draw_t - start_draw_t);
pm->send("uiDebug", msg);
} }
void NvgWindow::showEvent(QShowEvent *event) { void AnnotatedCameraWidget::showEvent(QShowEvent *event) {
CameraViewWidget::showEvent(event); CameraWidget::showEvent(event);
ui_update_params(uiState()); ui_update_params(uiState());
prev_draw_t = millis_since_boot(); prev_draw_t = millis_since_boot();

@ -25,7 +25,7 @@ private:
}; };
// container window for the NVG UI // container window for the NVG UI
class NvgWindow : public CameraViewWidget { class AnnotatedCameraWidget : public CameraWidget {
Q_OBJECT Q_OBJECT
Q_PROPERTY(float speed MEMBER speed); Q_PROPERTY(float speed MEMBER speed);
Q_PROPERTY(QString speedUnit MEMBER speedUnit); Q_PROPERTY(QString speedUnit MEMBER speedUnit);
@ -43,7 +43,7 @@ class NvgWindow : public CameraViewWidget {
Q_PROPERTY(int status MEMBER status); Q_PROPERTY(int status MEMBER status);
public: public:
explicit NvgWindow(VisionStreamType type, QWidget* parent = 0); explicit AnnotatedCameraWidget(VisionStreamType type, QWidget* parent = 0);
void updateState(const UIState &s); void updateState(const UIState &s);
private: private:
@ -68,6 +68,7 @@ private:
bool has_eu_speed_limit = false; bool has_eu_speed_limit = false;
bool v_ego_cluster_seen = false; bool v_ego_cluster_seen = false;
int status = STATUS_DISENGAGED; int status = STATUS_DISENGAGED;
std::unique_ptr<PubMaster> pm;
protected: protected:
void paintGL() override; void paintGL() override;
@ -97,7 +98,7 @@ private:
void paintEvent(QPaintEvent *event); void paintEvent(QPaintEvent *event);
void mousePressEvent(QMouseEvent* e) override; void mousePressEvent(QMouseEvent* e) override;
OnroadAlerts *alerts; OnroadAlerts *alerts;
NvgWindow *nvg; AnnotatedCameraWidget *nvg;
QColor bg = bg_colors[STATUS_DISENGAGED]; QColor bg = bg_colors[STATUS_DISENGAGED];
QWidget *map = nullptr; QWidget *map = nullptr;
QHBoxLayout* split; QHBoxLayout* split;

@ -21,10 +21,6 @@ QString getBrand() {
return Params().getBool("Passive") ? QObject::tr("dashcam") : QObject::tr("openpilot"); return Params().getBool("Passive") ? QObject::tr("dashcam") : QObject::tr("openpilot");
} }
QString getBrandVersion() {
return getBrand() + " v" + getVersion().left(14).trimmed();
}
QString getUserAgent() { QString getUserAgent() {
return "openpilot-" + getVersion(); return "openpilot-" + getVersion();
} }

@ -11,7 +11,6 @@
QString getVersion(); QString getVersion();
QString getBrand(); QString getBrand();
QString getBrandVersion();
QString getUserAgent(); QString getUserAgent();
std::optional<QString> getDongleId(); std::optional<QString> getDongleId();
QMap<QString, QString> getSupportedLanguages(); QMap<QString, QString> getSupportedLanguages();

@ -93,14 +93,14 @@ mat4 get_fit_view_transform(float widget_aspect_ratio, float frame_aspect_ratio)
} // namespace } // namespace
CameraViewWidget::CameraViewWidget(std::string stream_name, VisionStreamType type, bool zoom, QWidget* parent) : CameraWidget::CameraWidget(std::string stream_name, VisionStreamType type, bool zoom, QWidget* parent) :
stream_name(stream_name), stream_type(type), zoomed_view(zoom), QOpenGLWidget(parent) { stream_name(stream_name), stream_type(type), zoomed_view(zoom), QOpenGLWidget(parent) {
setAttribute(Qt::WA_OpaquePaintEvent); setAttribute(Qt::WA_OpaquePaintEvent);
connect(this, &CameraViewWidget::vipcThreadConnected, this, &CameraViewWidget::vipcConnected, Qt::BlockingQueuedConnection); connect(this, &CameraWidget::vipcThreadConnected, this, &CameraWidget::vipcConnected, Qt::BlockingQueuedConnection);
connect(this, &CameraViewWidget::vipcThreadFrameReceived, this, &CameraViewWidget::vipcFrameReceived); connect(this, &CameraWidget::vipcThreadFrameReceived, this, &CameraWidget::vipcFrameReceived);
} }
CameraViewWidget::~CameraViewWidget() { CameraWidget::~CameraWidget() {
makeCurrent(); makeCurrent();
if (isValid()) { if (isValid()) {
glDeleteVertexArrays(1, &frame_vao); glDeleteVertexArrays(1, &frame_vao);
@ -111,7 +111,7 @@ CameraViewWidget::~CameraViewWidget() {
doneCurrent(); doneCurrent();
} }
void CameraViewWidget::initializeGL() { void CameraWidget::initializeGL() {
initializeOpenGLFunctions(); initializeOpenGLFunctions();
program = std::make_unique<QOpenGLShaderProgram>(context()); program = std::make_unique<QOpenGLShaderProgram>(context());
@ -161,7 +161,7 @@ void CameraViewWidget::initializeGL() {
#endif #endif
} }
void CameraViewWidget::showEvent(QShowEvent *event) { void CameraWidget::showEvent(QShowEvent *event) {
frames.clear(); frames.clear();
if (!vipc_thread) { if (!vipc_thread) {
vipc_thread = new QThread(); vipc_thread = new QThread();
@ -171,7 +171,7 @@ void CameraViewWidget::showEvent(QShowEvent *event) {
} }
} }
void CameraViewWidget::hideEvent(QHideEvent *event) { void CameraWidget::hideEvent(QHideEvent *event) {
if (vipc_thread) { if (vipc_thread) {
vipc_thread->requestInterruption(); vipc_thread->requestInterruption();
vipc_thread->quit(); vipc_thread->quit();
@ -180,7 +180,7 @@ void CameraViewWidget::hideEvent(QHideEvent *event) {
} }
} }
void CameraViewWidget::updateFrameMat() { void CameraWidget::updateFrameMat() {
int w = width(), h = height(); int w = width(), h = height();
if (zoomed_view) { if (zoomed_view) {
@ -224,12 +224,12 @@ void CameraViewWidget::updateFrameMat() {
} }
} }
void CameraViewWidget::updateCalibration(const mat3 &calib) { void CameraWidget::updateCalibration(const mat3 &calib) {
calibration = calib; calibration = calib;
updateFrameMat(); updateFrameMat();
} }
void CameraViewWidget::paintGL() { void CameraWidget::paintGL() {
glClearColor(bg.redF(), bg.greenF(), bg.blueF(), bg.alphaF()); glClearColor(bg.redF(), bg.greenF(), bg.blueF(), bg.alphaF());
glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
@ -286,7 +286,7 @@ void CameraViewWidget::paintGL() {
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
} }
void CameraViewWidget::vipcConnected(VisionIpcClient *vipc_client) { void CameraWidget::vipcConnected(VisionIpcClient *vipc_client) {
makeCurrent(); makeCurrent();
frames.clear(); frames.clear();
stream_width = vipc_client->buffers[0].width; stream_width = vipc_client->buffers[0].width;
@ -339,7 +339,7 @@ void CameraViewWidget::vipcConnected(VisionIpcClient *vipc_client) {
updateFrameMat(); updateFrameMat();
} }
void CameraViewWidget::vipcFrameReceived(VisionBuf *buf, uint32_t frame_id) { void CameraWidget::vipcFrameReceived(VisionBuf *buf, uint32_t frame_id) {
frames.push_back(std::make_pair(frame_id, buf)); frames.push_back(std::make_pair(frame_id, buf));
while (frames.size() > FRAME_BUFFER_SIZE) { while (frames.size() > FRAME_BUFFER_SIZE) {
frames.pop_front(); frames.pop_front();
@ -347,7 +347,7 @@ void CameraViewWidget::vipcFrameReceived(VisionBuf *buf, uint32_t frame_id) {
update(); update();
} }
void CameraViewWidget::vipcThread() { void CameraWidget::vipcThread() {
VisionStreamType cur_stream_type = stream_type; VisionStreamType cur_stream_type = stream_type;
std::unique_ptr<VisionIpcClient> vipc_client; std::unique_ptr<VisionIpcClient> vipc_client;
VisionIpcBufExtra meta_main = {0}; VisionIpcBufExtra meta_main = {0};

@ -23,13 +23,13 @@
const int FRAME_BUFFER_SIZE = 5; const int FRAME_BUFFER_SIZE = 5;
static_assert(FRAME_BUFFER_SIZE <= YUV_BUFFER_COUNT); static_assert(FRAME_BUFFER_SIZE <= YUV_BUFFER_COUNT);
class CameraViewWidget : public QOpenGLWidget, protected QOpenGLFunctions { class CameraWidget : public QOpenGLWidget, protected QOpenGLFunctions {
Q_OBJECT Q_OBJECT
public: public:
using QOpenGLWidget::QOpenGLWidget; using QOpenGLWidget::QOpenGLWidget;
explicit CameraViewWidget(std::string stream_name, VisionStreamType stream_type, bool zoom, QWidget* parent = nullptr); explicit CameraWidget(std::string stream_name, VisionStreamType stream_type, bool zoom, QWidget* parent = nullptr);
~CameraViewWidget(); ~CameraWidget();
void setStreamType(VisionStreamType type) { stream_type = type; } void setStreamType(VisionStreamType type) { stream_type = type; }
void setBackgroundColor(const QColor &color) { bg = color; } void setBackgroundColor(const QColor &color) { bg = color; }
void setFrameId(int frame_id) { draw_frame_id = frame_id; } void setFrameId(int frame_id) { draw_frame_id = frame_id; }

@ -41,7 +41,7 @@ AbstractControl::AbstractControl(const QString &title, const QString &desc, cons
hlayout->addWidget(title_label); hlayout->addWidget(title_label);
// value next to control button // value next to control button
value = new QLabel(); value = new ElidedLabel();
value->setAlignment(Qt::AlignRight | Qt::AlignVCenter); value->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
value->setStyleSheet("color: #aaaaaa"); value->setStyleSheet("color: #aaaaaa");
hlayout->addWidget(value); hlayout->addWidget(value);
@ -70,7 +70,7 @@ AbstractControl::AbstractControl(const QString &title, const QString &desc, cons
} }
void AbstractControl::hideEvent(QHideEvent *e) { void AbstractControl::hideEvent(QHideEvent *e) {
if(description != nullptr) { if (description != nullptr) {
description->hide(); description->hide();
} }
} }

@ -65,7 +65,7 @@ protected:
QPushButton *title_label; QPushButton *title_label;
private: private:
QLabel *value; ElidedLabel *value;
QLabel *description = nullptr; QLabel *description = nullptr;
}; };

@ -3,6 +3,8 @@
#include <QScrollBar> #include <QScrollBar>
#include <QScroller> #include <QScroller>
// TODO: disable horizontal scrolling and resize
ScrollView::ScrollView(QWidget *w, QWidget *parent) : QScrollArea(parent) { ScrollView::ScrollView(QWidget *w, QWidget *parent) : QScrollArea(parent) {
setWidget(w); setWidget(w);
setWidgetResizable(true); setWidgetResizable(true);

File diff suppressed because it is too large Load Diff

@ -67,6 +67,29 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context>
<name>AnnotatedCameraWidget</name>
<message>
<source>km/h</source>
<translation>km/h</translation>
</message>
<message>
<source>mph</source>
<translation>mph</translation>
</message>
<message>
<source>MAX</source>
<translation></translation>
</message>
<message>
<source>SPEED</source>
<translation></translation>
</message>
<message>
<source>LIMIT</source>
<translation></translation>
</message>
</context>
<context> <context>
<name>ConfirmationDialog</name> <name>ConfirmationDialog</name>
<message> <message>
@ -406,29 +429,6 @@ location set</source>
<translation></translation> <translation></translation>
</message> </message>
</context> </context>
<context>
<name>NvgWindow</name>
<message>
<source>km/h</source>
<translation>km/h</translation>
</message>
<message>
<source>mph</source>
<translation>mph</translation>
</message>
<message>
<source>MAX</source>
<translation></translation>
</message>
<message>
<source>SPEED</source>
<translation></translation>
</message>
<message>
<source>LIMIT</source>
<translation></translation>
</message>
</context>
<context> <context>
<name>OffroadHome</name> <name>OffroadHome</name>
<message> <message>

@ -60,11 +60,34 @@
</message> </message>
<message> <message>
<source>Cellular Metered</source> <source>Cellular Metered</source>
<translation type="unfinished"></translation> <translation> </translation>
</message> </message>
<message> <message>
<source>Prevent large data uploads when on a metered connection</source> <source>Prevent large data uploads when on a metered connection</source>
<translation type="unfinished"></translation> <translation> </translation>
</message>
</context>
<context>
<name>AnnotatedCameraWidget</name>
<message>
<source>km/h</source>
<translation>km/h</translation>
</message>
<message>
<source>mph</source>
<translation>mph</translation>
</message>
<message>
<source>MAX</source>
<translation>MAX</translation>
</message>
<message>
<source>SPEED</source>
<translation>SPEED</translation>
</message>
<message>
<source>LIMIT</source>
<translation>LIMIT</translation>
</message> </message>
</context> </context>
<context> <context>
@ -406,29 +429,6 @@ location set</source>
<translation> </translation> <translation> </translation>
</message> </message>
</context> </context>
<context>
<name>NvgWindow</name>
<message>
<source>km/h</source>
<translation>km/h</translation>
</message>
<message>
<source>mph</source>
<translation>mph</translation>
</message>
<message>
<source>MAX</source>
<translation>MAX</translation>
</message>
<message>
<source>SPEED</source>
<translation>SPEED</translation>
</message>
<message>
<source>LIMIT</source>
<translation>LIMIT</translation>
</message>
</context>
<context> <context>
<name>OffroadHome</name> <name>OffroadHome</name>
<message> <message>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -67,6 +67,29 @@
<translation>Evite grandes uploads de dados quando estiver em uma conexão limitada</translation> <translation>Evite grandes uploads de dados quando estiver em uma conexão limitada</translation>
</message> </message>
</context> </context>
<context>
<name>AnnotatedCameraWidget</name>
<message>
<source>km/h</source>
<translation>km/h</translation>
</message>
<message>
<source>mph</source>
<translation>mph</translation>
</message>
<message>
<source>MAX</source>
<translation>LIMITE</translation>
</message>
<message>
<source>SPEED</source>
<translation>MAX</translation>
</message>
<message>
<source>LIMIT</source>
<translation>VELO</translation>
</message>
</context>
<context> <context>
<name>ConfirmationDialog</name> <name>ConfirmationDialog</name>
<message> <message>
@ -407,29 +430,6 @@ trabalho definido</translation>
<translation>Senha incorreta</translation> <translation>Senha incorreta</translation>
</message> </message>
</context> </context>
<context>
<name>NvgWindow</name>
<message>
<source>km/h</source>
<translation>km/h</translation>
</message>
<message>
<source>mph</source>
<translation>mph</translation>
</message>
<message>
<source>MAX</source>
<translation>LIMITE</translation>
</message>
<message>
<source>SPEED</source>
<translation>MAX</translation>
</message>
<message>
<source>LIMIT</source>
<translation>VELO</translation>
</message>
</context>
<context> <context>
<name>OffroadHome</name> <name>OffroadHome</name>
<message> <message>

File diff suppressed because it is too large Load Diff

@ -67,6 +67,29 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context>
<name>AnnotatedCameraWidget</name>
<message>
<source>km/h</source>
<translation>km/h</translation>
</message>
<message>
<source>mph</source>
<translation>mph</translation>
</message>
<message>
<source>MAX</source>
<translation></translation>
</message>
<message>
<source>SPEED</source>
<translation>SPEED</translation>
</message>
<message>
<source>LIMIT</source>
<translation>LIMIT</translation>
</message>
</context>
<context> <context>
<name>ConfirmationDialog</name> <name>ConfirmationDialog</name>
<message> <message>
@ -404,29 +427,6 @@ location set</source>
<translation></translation> <translation></translation>
</message> </message>
</context> </context>
<context>
<name>NvgWindow</name>
<message>
<source>km/h</source>
<translation>km/h</translation>
</message>
<message>
<source>mph</source>
<translation>mph</translation>
</message>
<message>
<source>MAX</source>
<translation></translation>
</message>
<message>
<source>SPEED</source>
<translation>SPEED</translation>
</message>
<message>
<source>LIMIT</source>
<translation>LIMIT</translation>
</message>
</context>
<context> <context>
<name>OffroadHome</name> <name>OffroadHome</name>
<message> <message>

@ -67,6 +67,29 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context>
<name>AnnotatedCameraWidget</name>
<message>
<source>km/h</source>
<translation>km/h</translation>
</message>
<message>
<source>mph</source>
<translation>mph</translation>
</message>
<message>
<source>MAX</source>
<translation></translation>
</message>
<message>
<source>SPEED</source>
<translation></translation>
</message>
<message>
<source>LIMIT</source>
<translation></translation>
</message>
</context>
<context> <context>
<name>ConfirmationDialog</name> <name>ConfirmationDialog</name>
<message> <message>
@ -406,29 +429,6 @@ location set</source>
<translation></translation> <translation></translation>
</message> </message>
</context> </context>
<context>
<name>NvgWindow</name>
<message>
<source>km/h</source>
<translation>km/h</translation>
</message>
<message>
<source>mph</source>
<translation>mph</translation>
</message>
<message>
<source>MAX</source>
<translation></translation>
</message>
<message>
<source>SPEED</source>
<translation></translation>
</message>
<message>
<source>LIMIT</source>
<translation></translation>
</message>
</context>
<context> <context>
<name>OffroadHome</name> <name>OffroadHome</name>
<message> <message>

@ -163,7 +163,8 @@ static void update_state(UIState *s) {
scene.longitudinal_control = sm["carParams"].getCarParams().getOpenpilotLongitudinalControl(); scene.longitudinal_control = sm["carParams"].getCarParams().getOpenpilotLongitudinalControl();
} }
if (sm.updated("wideRoadCameraState")) { if (sm.updated("wideRoadCameraState")) {
scene.light_sensor = 100.0f - sm["wideRoadCameraState"].getWideRoadCameraState().getExposureValPercent(); float scale = (sm["wideRoadCameraState"].getWideRoadCameraState().getSensor() == cereal::FrameData::ImageSensor::AR0321) ? 6.0f : 1.0f;
scene.light_sensor = std::max(100.0f - scale * sm["wideRoadCameraState"].getWideRoadCameraState().getExposureValPercent(), 0.0f);
} }
scene.started = sm["deviceState"].getDeviceState().getStarted() && scene.ignition; scene.started = sm["deviceState"].getDeviceState().getStarted() && scene.ignition;
} }

@ -19,15 +19,15 @@ int main(int argc, char *argv[]) {
{ {
QHBoxLayout *hlayout = new QHBoxLayout(); QHBoxLayout *hlayout = new QHBoxLayout();
layout->addLayout(hlayout); layout->addLayout(hlayout);
hlayout->addWidget(new CameraViewWidget("navd", VISION_STREAM_MAP, false)); hlayout->addWidget(new CameraWidget("navd", VISION_STREAM_MAP, false));
hlayout->addWidget(new CameraViewWidget("camerad", VISION_STREAM_ROAD, false)); hlayout->addWidget(new CameraWidget("camerad", VISION_STREAM_ROAD, false));
} }
{ {
QHBoxLayout *hlayout = new QHBoxLayout(); QHBoxLayout *hlayout = new QHBoxLayout();
layout->addLayout(hlayout); layout->addLayout(hlayout);
hlayout->addWidget(new CameraViewWidget("camerad", VISION_STREAM_DRIVER, false)); hlayout->addWidget(new CameraWidget("camerad", VISION_STREAM_DRIVER, false));
hlayout->addWidget(new CameraViewWidget("camerad", VISION_STREAM_WIDE_ROAD, false)); hlayout->addWidget(new CameraWidget("camerad", VISION_STREAM_WIDE_ROAD, false));
} }
return a.exec(); return a.exec();

@ -280,17 +280,25 @@ class Updater:
# Write out current and new version info # Write out current and new version info
def get_description(basedir: str) -> str: def get_description(basedir: str) -> str:
if not os.path.exists(basedir):
return ""
version = "" version = ""
branch = "" branch = ""
commit = "" commit = ""
commit_date = ""
try: try:
branch = self.get_branch(basedir) branch = self.get_branch(basedir)
commit = self.get_commit_hash(basedir) commit = self.get_commit_hash(basedir)[:7]
with open(os.path.join(basedir, "common", "version.h")) as f: with open(os.path.join(basedir, "common", "version.h")) as f:
version = f.read().split('"')[1] version = f.read().split('"')[1]
commit_unix_ts = run(["git", "show", "-s", "--format=%ct", "HEAD"], basedir).rstrip()
dt = datetime.datetime.fromtimestamp(int(commit_unix_ts))
commit_date = dt.strftime("%b %d")
except Exception: except Exception:
pass cloudlog.exception("updater.get_description")
return f"{version} / {branch} / {commit[:7]}" return f"{version} / {branch} / {commit} / {commit_date}"
self.params.put("UpdaterCurrentDescription", get_description(BASEDIR)) self.params.put("UpdaterCurrentDescription", get_description(BASEDIR))
self.params.put("UpdaterCurrentReleaseNotes", parse_release_notes(BASEDIR)) self.params.put("UpdaterCurrentReleaseNotes", parse_release_notes(BASEDIR))
self.params.put("UpdaterNewDescription", get_description(FINALIZED)) self.params.put("UpdaterNewDescription", get_description(FINALIZED))
@ -365,6 +373,7 @@ class Updater:
["git", "checkout", "--force", "--no-recurse-submodules", "-B", branch, "FETCH_HEAD"], ["git", "checkout", "--force", "--no-recurse-submodules", "-B", branch, "FETCH_HEAD"],
["git", "reset", "--hard"], ["git", "reset", "--hard"],
["git", "clean", "-xdff"], ["git", "clean", "-xdff"],
["git", "submodule", "sync"],
["git", "submodule", "init"], ["git", "submodule", "init"],
["git", "submodule", "update"], ["git", "submodule", "update"],
] ]

@ -21,7 +21,7 @@ class Proc:
PROCS = [ PROCS = [
Proc('camerad', 2.15), Proc('camerad', 2.15),
Proc('modeld', 1.15, atol=0.2), Proc('modeld', 1.15, atol=0.2),
Proc('dmonitoringmodeld', 0.35), Proc('dmonitoringmodeld', 0.4),
Proc('encoderd', 0.23), Proc('encoderd', 0.23),
] ]

@ -1 +1 @@
Subproject commit 870ea766eec7a38d7d590c81436f15271ba2667e Subproject commit 8e22d5ee675277181e1eff644dde9e844fc40fce

@ -6,13 +6,12 @@ openpilot is developed and tested on **Ubuntu 20.04**, which is the primary deve
## Setup your PC ## Setup your PC
First, clone openpilot: First, clone openpilot:
``` bash ``` bash
cd ~ cd ~
git clone https://github.com/commaai/openpilot.git git clone https://github.com/commaai/openpilot.git
cd openpilot cd openpilot
git submodule update --init git submodule update --init
``` ```
@ -26,10 +25,10 @@ tools/ubuntu_setup.sh
tools/mac_setup.sh tools/mac_setup.sh
``` ```
Activate a shell with the install Python dependencies: Activate a shell with the Python dependencies installed:
``` bash ``` bash
cd openpilot && pipenv shell cd openpilot && poetry shell
``` ```
Build openpilot with this command: Build openpilot with this command:
@ -43,7 +42,7 @@ Neither openpilot nor any of the tools are developed or tested on Windows, but t
Follow [these instructions](https://docs.microsoft.com/en-us/windows/wsl/install) to setup the WSL and install the `Ubuntu-20.04` distribution. Once your Ubuntu WSL environment is setup, follow the Linux setup instructions to finish setting up your environment. Follow [these instructions](https://docs.microsoft.com/en-us/windows/wsl/install) to setup the WSL and install the `Ubuntu-20.04` distribution. Once your Ubuntu WSL environment is setup, follow the Linux setup instructions to finish setting up your environment.
GUI applications do not work with WSL out of the box. You will have to either [upgrade your system to Windows 11](https://docs.microsoft.com/en-us/windows/wsl/tutorials/gui-apps) or [set up an Xorg server](https://techcommunity.microsoft.com/t5/windows-dev-appconsult/running-wsl-gui-apps-on-windows-10/ba-p/1493242). GUI applications do not work with WSL out of the box. You will have to either [upgrade your system to Windows 11](https://docs.microsoft.com/en-us/windows/wsl/tutorials/gui-apps) or [set up an Xorg server](https://techcommunity.microsoft.com/t5/windows-dev-appconsult/running-wsl-gui-apps-on-windows-10/ba-p/1493242).
## CTF ## CTF

@ -3,3 +3,5 @@ moc_*
_cabana _cabana
settings settings
car_fingerprint_to_dbc.json

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save