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. 5
      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
# ~/github_brew_cache_entries.txt
# /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-
# - name: Brew link restored dependencies
# run: |
@ -121,11 +121,11 @@ jobs:
# - name: Build openpilot
# run: |
# source tools/openpilot_env.sh
# pipenv run selfdrive/manager/build.py
# poetry run selfdrive/manager/build.py
#
# # cleanup 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
# if: steps.dependency-cache.outputs.cache-hit != 'true'
# run: |

2
.gitignore vendored

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

2
.gitmodules vendored

@ -18,4 +18,4 @@
url = ../../commaai/body.git
[submodule "tinygrad"]
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
language: script
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 LC_ALL en_US.UTF-8
ENV PIPENV_SYSTEM=1
ENV POETRY_VIRTUALENVS_CREATE=false
ENV PYENV_VERSION=3.8.10
ENV PYENV_ROOT="/root/.pyenv"
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/
RUN cd /tmp && \
tools/ubuntu_setup.sh && \
rm -rf /var/lib/apt/lists/* && \
rm -rf /tmp/* && \
rm -rf /root/.cache && \
pip uninstall -y pipenv && \
pip uninstall -y poetry && \
# remove unused architectures from gcc for panda
cd /usr/lib/gcc/arm-none-eabi/9.2.1 && \
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
* 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
* 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
* Multi-language in navigation
* Matched speeds shown on car's dash
@ -12,6 +14,8 @@ Version 0.8.17 (2022-XX-XX)
* Border turns grey while overriding steering
* Added button to bookmark events while driving; view them later in comma connect
* 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)
========================

@ -327,6 +327,7 @@ qt_flags = [
qt_env['CXXFLAGS'] += qt_flags
qt_env['LIBPATH'] += ['#selfdrive/ui']
qt_env['LIBS'] = qt_libs
qt_env['QT_MOCHPREFIX'] = cache_dir + '/moc_files/moc_'
if GetOption("clazy"):
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.
# 208 Supported Cars
# 211 Supported Cars
|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|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|
|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|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|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|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|
|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|
@ -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|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|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 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|
@ -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|
|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 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|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 (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|
@ -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|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|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|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|
@ -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 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|
|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|
|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|

@ -4,16 +4,11 @@ ENV PYTHONUNBUFFERED 1
ENV OPENPILOT_PATH /home/batman/openpilot/
ENV PYTHONPATH ${OPENPILOT_PATH}:${PYTHONPATH}
ENV POETRY_VIRUALENVS_CREATE false
RUN mkdir -p ${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 ./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/accel/opencl/*
tinygrad_repo/extra/onnx.py
tinygrad_repo/extra/thneed.py
tinygrad_repo/extra/utils.py
tinygrad_repo/tinygrad/llops/ops_gpu.py
tinygrad_repo/tinygrad/llops/ops_opencl.py

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

@ -76,7 +76,7 @@ interfaces = load_interfaces(interface_names)
# **** for use live only ****
def fingerprint(logcan, sendcan):
def fingerprint(logcan, sendcan, num_pandas):
fixed_fingerprint = os.environ.get('FINGERPRINT', "")
skip_fw_query = os.environ.get('SKIP_FW_QUERY', False)
ecu_rx_addrs = set()
@ -100,7 +100,7 @@ def fingerprint(logcan, sendcan):
cloudlog.warning("Getting VIN & FW versions")
vin_rx_addr, vin = get_vin(logcan, sendcan, bus)
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
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
def get_car(logcan, sendcan):
candidate, fingerprints, vin, car_fw, source, exact_match = fingerprint(logcan, sendcan)
def get_car(logcan, sendcan, num_pandas=1):
candidate, fingerprints, vin, car_fw, source, exact_match = fingerprint(logcan, sendcan, num_pandas)
if candidate is None:
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
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"""
all_car_fw = []
brand_matches = get_brand_ecu_matches(ecu_rx_addrs)
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)
# Try to match using FW returned from this brand only
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
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()
# 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_chunk in chunks(addr):
for brand, r in requests:
# Skip query if no panda available
if r.bus > num_pandas * 4 - 1:
continue
try:
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)]
@ -292,6 +296,7 @@ if __name__ == "__main__":
args = parser.parse_args()
logcan = messaging.sub_sock('can')
pandaStates_sock = messaging.sub_sock('pandaStates')
sendcan = messaging.pub_sock('sendcan')
extra: Any = None
@ -305,6 +310,7 @@ if __name__ == "__main__":
extra = {"any": {"debug": extra}}
time.sleep(1.)
num_pandas = len(messaging.recv_one_retry(pandaStates_sock).pandaStates)
t = time.time()
print("Getting vin...")
@ -314,7 +320,7 @@ if __name__ == "__main__":
print()
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)
print()

@ -10,6 +10,9 @@ from selfdrive.car.gm.values import DBC, CanBus, CarControllerParams, CruiseButt
VisualAlert = car.CarControl.HUDControl.VisualAlert
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:
def __init__(self, dbc_name, CP, VM):
@ -19,7 +22,9 @@ class CarController:
self.apply_gas = 0
self.apply_brake = 0
self.frame = 0
self.last_steer_frame = 0
self.last_button_frame = 0
self.cancel_counter = 0
self.lka_steering_cmd_counter = 0
self.sent_lka_steering_cmd = False
@ -42,15 +47,21 @@ class CarController:
# Send CAN commands.
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
# next Panda loopback confirmation in the current CS frame.
if CS.loopback_lka_steering_cmd_updated:
self.lka_steering_cmd_counter += 1
self.sent_lka_steering_cmd = True
elif (self.frame % self.params.STEER_STEP) == 0:
# Initialize ASCMLKASteeringCmd counter using the camera
if not self.sent_lka_steering_cmd and self.CP.networkLocation == NetworkLocation.fwdCamera:
elif (self.frame - self.last_steer_frame) >= steer_step:
# Initialize ASCMLKASteeringCmd counter using the camera until we get a msg on the bus
if init_lka_counter:
self.lka_steering_cmd_counter = CS.camera_lka_steering_cmd_counter + 1
if CC.latActive:
@ -59,6 +70,7 @@ class CarController:
else:
apply_steer = 0
self.last_steer_frame = self.frame
self.apply_steer_last = apply_steer
idx = self.lka_steering_cmd_counter % 4
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
if self.frame % 4 == 0:
if not CC.longActive:
# Stock ECU sends max regen when not enabled
self.apply_gas = self.params.MAX_ACC_REGEN
# ASCM sends max regen when not enabled
self.apply_gas = self.params.INACTIVE_REGEN
self.apply_brake = 0
else:
if self.CP.carFingerprint in EV_CAR:
@ -111,12 +123,21 @@ class CarController:
can_sends += gmcan.create_adas_keepalive(CanBus.POWERTRAIN)
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
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
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
# alarming orange icon when approaching torque limit.
# If not sent again, LKA icon disappears in about 5 seconds.

@ -1,3 +1,4 @@
import copy
from cereal import car
from common.conversions import Conversions as CV
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
NetworkLocation = car.CarParams.NetworkLocation
STANDSTILL_THRESHOLD = 10 * 0.0311 * CV.KPH_TO_MS
class CarState(CarStateBase):
@ -25,9 +27,10 @@ class CarState(CarStateBase):
self.prev_cruise_buttons = self.cruise_buttons
self.cruise_buttons = pt_cp.vl["ASCMSteeringButton"]["ACCButtons"]
self.buttons_counter = pt_cp.vl["ASCMSteeringButton"]["RollingCounter"]
self.pscm_status = copy.copy(pt_cp.vl["PSCMStatus"])
# 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:
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.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:
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
# https://static.nhtsa.gov/odi/tsbs/2017/MC-10137629-9999.pdf
ret.brake = pt_cp.vl["ECMAcceleratorPos"]["BrakePedalPos"]
if self.CP.networkLocation != NetworkLocation.fwdCamera:
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
ret.brakePressed = ret.brake >= 8
# Regen braking is braking
if self.CP.transmissionType == TransmissionType.direct:
@ -96,9 +95,7 @@ class CarState(CarStateBase):
ret.cruiseState.standstill = pt_cp.vl["AcceleratorPedal2"]["CruiseState"] == AccState.STANDSTILL
if self.CP.networkLocation == NetworkLocation.fwdCamera:
ret.cruiseState.speed = cam_cp.vl["ASCMActiveCruiseControlStatus"]["ACCSpeedSetpoint"] * CV.KPH_TO_MS
ret.stockAeb = cam_cp.vl["AEBCmd"]["AEBCmdActive"] != 0
ret.stockFcw = cam_cp.vl["ASCMActiveCruiseControlStatus"]["FCWAlert"] != 0
return ret
@ -110,7 +107,6 @@ class CarState(CarStateBase):
signals += [
("AEBCmdActive", "AEBCmd"),
("RollingCounter", "ASCMLKASteeringCmd"),
("FCWAlert", "ASCMActiveCruiseControlStatus"),
("ACCSpeedSetpoint", "ASCMActiveCruiseControlStatus"),
]
checks += [
@ -148,6 +144,11 @@ class CarState(CarStateBase):
("LKADriverAppldTrq", "PSCMStatus"),
("LKATorqueDelivered", "PSCMStatus"),
("LKATorqueDeliveredStatus", "PSCMStatus"),
("HandsOffSWlDetectionStatus", "PSCMStatus"),
("HandsOffSWDetectionMode", "PSCMStatus"),
("LKATotalTorqueDelivered", "PSCMStatus"),
("PSCMStatusChecksum", "PSCMStatus"),
("RollingCounter", "PSCMStatus"),
("TractionControlOn", "ESPStatus"),
("ParkBrake", "VehicleIgnitionAlt"),
("CruiseMainOn", "ECMEngineStatus"),

@ -1,5 +1,6 @@
from selfdrive.car import make_can_msg
def create_buttons(packer, bus, idx, button):
values = {
"ACCButtons": button,
@ -7,8 +8,15 @@ def create_buttons(packer, bus, idx, button):
}
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 = {
"LKASteeringCmdActive": lkas_active,
"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)
def create_adas_keepalive(bus):
dat = b"\x00\x00\x00\x00\x00\x00\x00"
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 = {
"GasRegenCmdActive": acc_engaged,
"GasRegenCmdActive": enabled,
"RollingCounter": idx,
"GasRegenCmdActiveInv": 1 - acc_engaged,
"GasRegenCmdActiveInv": 1 - enabled,
"GasRegenCmd": throttle,
"GasRegenFullStopActive": at_full_stop,
"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)
def create_friction_brake_command(packer, bus, apply_brake, idx, near_stop, at_full_stop):
mode = 0x1
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
values = {
"RollingCounter" : idx,
"FrictionBrakeMode" : mode,
"RollingCounter": idx,
"FrictionBrakeMode": mode,
"FrictionBrakeChecksum": checksum,
"FrictionBrakeCmd" : -apply_brake
"FrictionBrakeCmd": -apply_brake
}
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)
values = {
"ACCAlwaysOne" : 1,
"ACCResumeButton" : 0,
"ACCSpeedSetpoint" : target_speed,
"ACCGapLevel" : 3 * acc_engaged, # 3 "far", 0 "inactive"
"ACCCmdActive" : acc_engaged,
"ACCAlwaysOne2" : 1,
"ACCLeadCar" : lead_car_in_sight,
"ACCAlwaysOne": 1,
"ACCResumeButton": 0,
"ACCSpeedSetpoint": target_speed,
"ACCGapLevel": 3 * enabled, # 3 "far", 0 "inactive"
"ACCCmdActive": enabled,
"ACCAlwaysOne2": 1,
"ACCLeadCar": lead_car_in_sight,
"FCWAlert": 0x3 if fcw else 0
}
return packer.make_can_msg("ASCMActiveCruiseControlStatus", bus, values)
def create_adas_time_status(bus, tt, idx):
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 = chksum & 0xfff
dat += [0x40 + (chksum >> 8), chksum & 0xff, 0x12]
return make_can_msg(0xa1, bytes(dat), bus)
def create_adas_steering_status(bus, idx):
dat = [idx << 6, 0xf0, 0x20, 0, 0, 0]
chksum = 0x60 + sum(dat)
dat += [chksum >> 8, chksum & 0xff]
return make_can_msg(0x306, bytes(dat), bus)
def create_adas_accelerometer_speed_status(bus, speed_ms, idx):
spd = int(speed_ms * 16) & 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]
return make_can_msg(0x308, bytes(dat), bus)
def create_adas_headlights_status(packer, bus):
values = {
"Always42": 0x42,
@ -115,6 +131,7 @@ def create_adas_headlights_status(packer, bus):
}
return packer.make_can_msg("ASCMHeadlight", bus, values)
def create_lka_icon_command(bus, active, critical, steer):
if active and steer == 1:
if critical:

@ -62,11 +62,14 @@ class CarInterface(CarInterfaceBase):
ret.radarOffCan = True # no radar
ret.pcmCruise = True
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM
ret.minEnableSpeed = 5 * CV.KPH_TO_MS
else: # ASCM, OBD-II harness
ret.openpilotLongitudinalControl = True
ret.networkLocation = NetworkLocation.gateway
ret.radarOffCan = False
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 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.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:
ret.mass = 1607. + STD_CARGO_KG
ret.wheelbase = 2.69
@ -153,7 +153,6 @@ class CarInterface(CarInterfaceBase):
tire_stiffness_factor = 1.0
elif candidate in (CAR.BOLT_EV, CAR.BOLT_EUV):
ret.minEnableSpeed = -1
ret.mass = 1669. + STD_CARGO_KG
ret.wheelbase = 2.63779
ret.steerRatio = 16.8
@ -163,7 +162,6 @@ class CarInterface(CarInterfaceBase):
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.SILVERADO:
ret.minEnableSpeed = -1
ret.mass = 2200. + STD_CARGO_KG
ret.wheelbase = 3.75
ret.steerRatio = 16.3
@ -172,7 +170,6 @@ class CarInterface(CarInterfaceBase):
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.EQUINOX:
ret.minEnableSpeed = -1
ret.mass = 3500. * CV.LB_TO_KG + STD_CARGO_KG
ret.wheelbase = 2.72
ret.steerRatio = 14.4
@ -207,19 +204,16 @@ class CarInterface(CarInterfaceBase):
GearShifter.eco, GearShifter.manumatic],
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)
if ret.cruiseState.standstill:
events.add(EventName.resumeRequired)
if ret.vEgo < self.CP.minSteerSpeed:
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()
return ret

@ -11,7 +11,8 @@ Ecu = car.CarParams.Ecu
class CarControllerParams:
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_DOWN = 17
STEER_DRIVER_ALLOWANCE = 50
@ -30,6 +31,7 @@ class CarControllerParams:
ZERO_GAS = 2048 # Coasting
MAX_BRAKE = 400 # ~ -4.0 m/s^2 with 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
# perform the closed loop control, and might need some

@ -105,7 +105,6 @@ class Footnote(Enum):
@dataclass
class HondaCarInfo(CarInfo):
package: str = "Honda Sensing"
min_steer_speed: float = 12. * CV.MPH_TO_MS
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),
],
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: [
HondaCarInfo("Honda Civic 2019-21", "All", "https://www.youtube.com/watch?v=4Iz1Mz5LGF8", [Footnote.CIVIC_DIESEL], min_steer_speed=2. * CV.MPH_TO_MS, harness=Harness.bosch_a),
HondaCarInfo("Honda Civic Hatchback 2017-21", harness=Harness.bosch_a),
HondaCarInfo("Honda Civic 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", min_steer_speed=12. * CV.MPH_TO_MS, harness=Harness.bosch_a),
],
CAR.CIVIC_BOSCH_DIESEL: None, # same platform
CAR.CIVIC_2022: [
HondaCarInfo("Honda Civic 2022", "All", min_steer_speed=0., harness=Harness.bosch_b),
HondaCarInfo("Honda Civic Hatchback 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", 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.CRV: HondaCarInfo("Honda CR-V 2015-16", "Touring Trim", harness=Harness.nidec),
CAR.CRV_5G: HondaCarInfo("Honda CR-V 2017-22", harness=Harness.bosch_a),
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", 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_HYBRID: HondaCarInfo("Honda CR-V Hybrid 2017-19", harness=Harness.bosch_a),
CAR.FIT: HondaCarInfo("Honda Fit 2018-20", harness=Harness.nidec),
CAR.FREED: HondaCarInfo("Honda Freed 2020", harness=Harness.nidec),
CAR.HRV: HondaCarInfo("Honda HR-V 2019-22", harness=Harness.nidec),
CAR.ODYSSEY: HondaCarInfo("Honda Odyssey 2018-20", min_steer_speed=0., harness=Harness.nidec),
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", min_steer_speed=12. * CV.MPH_TO_MS, 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", min_steer_speed=12. * CV.MPH_TO_MS, harness=Harness.nidec),
CAR.ODYSSEY: HondaCarInfo("Honda Odyssey 2018-20", harness=Harness.nidec),
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.PILOT: HondaCarInfo("Honda Pilot 2016-22", harness=Harness.nidec),
CAR.PASSPORT: HondaCarInfo("Honda Passport 2019-21", "All", harness=Harness.nidec),
CAR.RIDGELINE: HondaCarInfo("Honda Ridgeline 2017-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", min_steer_speed=12. * CV.MPH_TO_MS, 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.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-TEG-A310\x00\x00',
],
(Ecu.fwdCamera, 0x18dab0f1, None): [
(Ecu.fwdRadar, 0x18dab0f1, None): [
b'36161-TBA-A020\x00\x00',
b'36161-TBA-A030\x00\x00',
b'36161-TBA-A040\x00\x00',
@ -965,7 +964,7 @@ FW_VERSIONS = {
b'77959-THR-A110\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-A030\x00\x00',
b'36161-THR-A110\x00\x00',
@ -1069,7 +1068,7 @@ FW_VERSIONS = {
b'39990-TG7-A070\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-A520\x00\x00',
b'36161-TG7-A630\x00\x00',
@ -1177,7 +1176,7 @@ FW_VERSIONS = {
b'57114-TX5-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-TX4-A030\x00\x00',
],
@ -1274,7 +1273,7 @@ FW_VERSIONS = {
b'39990-T6Z-A030\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-A310\x00\x00',
b'36161-T6Z-A420\x00\x00',

@ -90,13 +90,27 @@ class CarController:
addr, bus = 0x730, 5
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
if self.CP.carFingerprint in CANFD_CAR:
hda2 = self.CP.flags & HyundaiFlags.CANFD_HDA2
hda2_long = hda2 and self.CP.openpilotLongitudinalControl
# 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
if self.frame % 5 == 0 and hda2:
@ -121,29 +135,19 @@ class CarController:
self.last_button_frame = self.frame
else:
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
# cruise standstill 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):
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
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,
torque_fault, CS.lkas11, sys_warning, sys_state, CC.enabled,
hud_control.leftLaneVisible, hud_control.rightLaneVisible,

@ -159,7 +159,7 @@ class CarState(CarStateBase):
elif self.CP.carFingerprint in HYBRID_CAR:
ret.gas = cp.vl["ACCELERATOR_ALT"]["ACCELERATOR_PEDAL"] / 1023.
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.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"],
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.enabled = cp.vl["SCC1"]["CRUISE_ACTIVE"] == 1
self.is_metric = cp.vl["CLUSTER_INFO"]["DISTANCE_UNIT"] != 1
if not self.CP.openpilotLongitudinalControl:
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
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.enabled = cp_cruise_info.vl["CRUISE_INFO"]["CRUISE_STATUS"] != 0
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"
@ -415,7 +418,6 @@ class CarState(CarStateBase):
("WHEEL_SPEED_4", "WHEEL_SPEEDS"),
("GEAR", "GEAR_SHIFTER"),
("BRAKE_PRESSED", "BRAKE"),
("STEERING_RATE", "STEERING_SENSORS"),
("STEERING_ANGLE", "STEERING_SENSORS"),
@ -423,7 +425,8 @@ class CarState(CarStateBase):
("STEERING_OUT_TORQUE", "MDPS"),
("LKA_FAULT", "MDPS"),
("CRUISE_ACTIVE", "SCC1"),
("DriverBraking", "TCS"),
("COUNTER", cruise_btn_msg),
("CRUISE_BUTTONS", cruise_btn_msg),
("ADAPTIVE_CRUISE_MAIN_BTN", cruise_btn_msg),
@ -443,15 +446,25 @@ class CarState(CarStateBase):
("BRAKE", 100),
("STEERING_SENSORS", 100),
("MDPS", 100),
("SCC1", 50),
("TCS", 50),
(cruise_btn_msg, 50),
("CLUSTER_INFO", 4),
("BLINKERS", 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:
signals += [
("CRUISE_STATUS", "CRUISE_INFO"),
("SET_SPEED", "CRUISE_INFO"),
("CRUISE_STANDSTILL", "CRUISE_INFO"),
]

@ -3,7 +3,7 @@ from selfdrive.car.hyundai.values import HyundaiFlags
def get_e_can_bus(CP):
# 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.
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)
def create_buttons(packer, cnt, btn):
def create_buttons(packer, CP, cnt, btn):
values = {
"COUNTER": cnt,
"SET_ME_1": 1,
"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):
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.disable_ecu import disable_ecu
Ecu = car.CarParams.Ecu
ButtonType = car.CarState.ButtonEvent.Type
EventName = car.CarEvent.EventName
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 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.
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:
# detect HDA2 with LKAS message
if 0x50 in fingerprint[6]:
# detect HDA2 with ADAS Driving ECU
if Ecu.adas in [fw.ecu for fw in car_fw]:
ret.flags |= HyundaiFlags.CANFD_HDA2.value
else:
# non-HDA2
@ -44,141 +45,92 @@ class CarInterface(CarInterfaceBase):
ret.steerActuatorDelay = 0.1 # Default delay
ret.steerLimitTimer = 0.4
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):
ret.lateralTuning.pid.kf = 0.00005
ret.mass = 3982. * CV.LB_TO_KG + STD_CARGO_KG
ret.wheelbase = 2.766
# Values from optimizer
ret.steerRatio = 16.55 # 13.8 is spec end-to-end
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):
ret.mass = 1513. + STD_CARGO_KG
ret.wheelbase = 2.84
ret.steerRatio = 13.27 * 1.15 # 15% higher at the center seems reasonable
tire_stiffness_factor = 0.65
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.SONATA_LF:
ret.lateralTuning.pid.kf = 0.00005
ret.mass = 4497. * CV.LB_TO_KG
ret.wheelbase = 2.804
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:
ret.lateralTuning.pid.kf = 0.00005
ret.mass = 1999. + STD_CARGO_KG
ret.wheelbase = 2.90
ret.steerRatio = 15.6 * 1.15
tire_stiffness_factor = 0.63
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate in (CAR.ELANTRA, CAR.ELANTRA_GT_I30):
ret.lateralTuning.pid.kf = 0.00006
elif candidate == CAR.ELANTRA:
ret.mass = 1275. + STD_CARGO_KG
ret.wheelbase = 2.7
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
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
elif candidate == CAR.ELANTRA_2021:
ret.mass = (2800. * CV.LB_TO_KG) + STD_CARGO_KG
ret.wheelbase = 2.72
ret.steerRatio = 12.9
tire_stiffness_factor = 0.65
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.ELANTRA_HEV_2021:
ret.mass = (3017. * CV.LB_TO_KG) + STD_CARGO_KG
ret.wheelbase = 2.72
ret.steerRatio = 12.9
tire_stiffness_factor = 0.65
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.HYUNDAI_GENESIS:
ret.lateralTuning.pid.kf = 0.00005
ret.mass = 2060. + STD_CARGO_KG
ret.wheelbase = 3.01
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
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.wheelbase = 2.6
ret.steerRatio = 13.42 # Spec
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):
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.wheelbase = 2.7
ret.steerRatio = 13.73 # Spec
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):
ret.minSteerSpeed = 32 * CV.MPH_TO_MS
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.wheelbase = 2.7
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
elif candidate == CAR.VELOSTER:
ret.lateralTuning.pid.kf = 0.00005
ret.mass = 3558. * CV.LB_TO_KG
ret.wheelbase = 2.80
ret.steerRatio = 13.75 * 1.15
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:
ret.lateralTuning.pid.kf = 0.00005
ret.mass = 3520. * CV.LB_TO_KG
ret.wheelbase = 2.67
ret.steerRatio = 14.00 * 1.15
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:
ret.mass = 1680. + STD_CARGO_KG # average of all 3 trims
ret.wheelbase = 2.756
ret.steerRatio = 16.
tire_stiffness_factor = 0.385
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
# Kia
elif candidate == CAR.KIA_SORENTO:
ret.lateralTuning.pid.kf = 0.00005
ret.mass = 1985. + STD_CARGO_KG
ret.wheelbase = 2.78
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):
ret.lateralTuning.pid.kf = 0.00006
ret.mass = 1737. + STD_CARGO_KG
ret.wheelbase = 2.7
ret.steerRatio = 13.9 if CAR.KIA_NIRO_HEV_2021 else 13.73 # Spec
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:
ret.minSteerSpeed = 32 * CV.MPH_TO_MS
elif candidate == CAR.KIA_SELTOS:
@ -186,15 +138,6 @@ class CarInterface(CarInterfaceBase):
ret.wheelbase = 2.63
ret.steerRatio = 14.56
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):
ret.mass = 3558. * CV.LB_TO_KG
ret.wheelbase = 2.80
@ -202,87 +145,58 @@ class CarInterface(CarInterfaceBase):
tire_stiffness_factor = 0.5
if candidate == CAR.KIA_OPTIMA_G4:
ret.minSteerSpeed = 32 * CV.MPH_TO_MS
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.KIA_STINGER:
ret.lateralTuning.pid.kf = 0.00005
ret.mass = 1825. + STD_CARGO_KG
ret.wheelbase = 2.78
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:
ret.lateralTuning.pid.kf = 0.00005
ret.mass = 3558. * CV.LB_TO_KG
ret.wheelbase = 2.80
ret.steerRatio = 13.75
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:
ret.lateralTuning.pid.kf = 0.00005
ret.mass = 1450. + STD_CARGO_KG
ret.wheelbase = 2.65
ret.steerRatio = 13.75
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:
ret.lateralTuning.pid.kf = 0.00005
ret.mass = 3228. * CV.LB_TO_KG
ret.wheelbase = 2.85
ret.steerRatio = 13.27 # 2021 Kia K5 Steering Ratio (all trims)
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:
ret.mass = 2055 + STD_CARGO_KG
ret.wheelbase = 2.9
ret.steerRatio = 16.
tire_stiffness_factor = 0.65
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.IONIQ_5:
ret.mass = 2012 + STD_CARGO_KG
ret.wheelbase = 3.0
ret.steerRatio = 16.
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
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.mass = 1640.0 + STD_CARGO_KG
ret.wheelbase = 2.84
ret.steerRatio = 13.56
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.wheelbase = 2.83
ret.steerRatio = 12.9
elif candidate == CAR.GENESIS_G80:
ret.lateralTuning.pid.kf = 0.00005
ret.mass = 2060. + STD_CARGO_KG
ret.wheelbase = 3.01
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:
ret.mass = 2200
ret.wheelbase = 3.15
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 ***
if candidate in CANFD_CAR:
@ -305,6 +219,13 @@ class CarInterface(CarInterfaceBase):
ret.vEgoStarting = 0.1
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 ***
if candidate in CANFD_CAR:
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.noOutput),
@ -315,8 +236,6 @@ class CarInterface(CarInterfaceBase):
if ret.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
ret.safetyConfigs[1].safetyParam |= Panda.FLAG_HYUNDAI_CANFD_ALT_BUTTONS
else:
ret.enableBsm = 0x58b in fingerprint[0]
if candidate in LEGACY_SAFETY_MODE_CAR:
# 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)]

@ -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.
# 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.KIA_OPTIMA_H, CAR.KIA_SORENTO, CAR.KIA_STINGER):
CAR.KIA_OPTIMA_H, CAR.KIA_SORENTO):
self.STEER_MAX = 255
# Default for most HKG
@ -54,7 +54,6 @@ class CAR:
ELANTRA = "HYUNDAI ELANTRA 2017"
ELANTRA_2021 = "HYUNDAI ELANTRA 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"
IONIQ = "HYUNDAI IONIQ HYBRID 2017-2019"
IONIQ_HEV_2022 = "HYUNDAI IONIQ HYBRID 2020-2022"
@ -90,6 +89,7 @@ class CAR:
KIA_OPTIMA_H = "KIA OPTIMA HYBRID 2017 & SPORTS 2019"
KIA_SELTOS = "KIA SELTOS 2021"
KIA_SORENTO = "KIA SORENTO GT LINE 2018"
KIA_SPORTAGE_HYBRID_5TH_GEN = "KIA SPORTAGE HYBRID 5TH GEN"
KIA_STINGER = "KIA STINGER GT2 2018"
KIA_CEED = "KIA CEED INTRO ED 2019"
KIA_EV6 = "KIA EV6 2022"
@ -107,13 +107,13 @@ class HyundaiCarInfo(CarInfo):
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_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.ELANTRA_GT_I30: [
CAR.ELANTRA: [
HyundaiCarInfo("Hyundai Elantra 2017-19", min_enable_speed=19 * CV.MPH_TO_MS, harness=Harness.hyundai_b),
HyundaiCarInfo("Hyundai Elantra GT 2017-19", 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.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
@ -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 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_CEED: HyundaiCarInfo("Kia Ceed 2019", harness=Harness.hyundai_e),
CAR.KIA_EV6: [
@ -197,15 +198,6 @@ FINGERPRINTS = {
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
}],
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: [{
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(
requests=[
# TODO: minimize shared whitelists for CAN and cornerRadar for CAN-FD
# CAN queries (OBD-II port)
Request(
[HYUNDAI_VERSION_REQUEST_LONG],
[HYUNDAI_VERSION_RESPONSE],
whitelist_ecus=[Ecu.transmission, Ecu.eps, Ecu.abs, Ecu.fwdRadar, Ecu.fwdCamera],
),
Request(
[HYUNDAI_VERSION_REQUEST_MULTI],
[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=[
(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\x82CKJN3TMSDE0B\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): [
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\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\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: {
(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 FHCUP 1.00 1.04 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 \x0b 101\x19\x03\x17 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\x10 58910-S8360',
b'\xf1\x00LX ESC \x0b 104 \x10\x16 58910-S8360',
@ -794,6 +810,7 @@ FW_VERSIONS = {
],
(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-S8000 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\x00ON MDPS C 1.00 1.00 56340-S9000 8B13',
@ -810,6 +827,7 @@ FW_VERSIONS = {
],
(Ecu.transmission, 0x7e1, None): [
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\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',
@ -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',
],
},
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: {
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00CN7_ SCC F-CUP 1.00 1.01 99110-AA000 ',
@ -1321,15 +1356,6 @@ FW_VERSIONS = {
],
},
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): [
b'\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: {
(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): [
b'\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: {
(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-N9220 14K',
],
(Ecu.eps, 0x7d4, None): [
b'\xf1\x00NX4 MDPS C 1.00 1.01 56300-P0100 2228',
(Ecu.fwdRadar, 0x7d0, None): [
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): [
b'\xf1\x00PSBG2441 G19_Rev\x00\x00\x00SNX4T16XXHS01NS2lS\xdfa',
b'\xf1\x8795441-3D220\x00\xf1\x81G19_Rev\x00\x00\x00\xf1\x00PSBG2441 G19_Rev\x00\x00\x00SNX4T16XXHS01NS2lS\xdfa',
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00NQ5__ 1.01 1.03 99110-CH000 ',
],
},
}
@ -1384,20 +1402,20 @@ CHECKSUM = {
FEATURES = {
# 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_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
"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
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}
# 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_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_2020: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'),
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.TUCSON_HYBRID_4TH_GEN: 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.MAZDA6: MazdaCarInfo("Mazda 6 2017-20"),
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): [
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): [
b'PYB2-21PS1-H\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
@ -98,13 +99,15 @@ FW_VERSIONS = {
},
CAR.CX5: {
(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-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'K319-3210X-A-00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.engine, 0x7e0, None): [
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'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',
@ -146,6 +149,7 @@ FW_VERSIONS = {
],
(Ecu.transmission, 0x7e1, None): [
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-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',

@ -23,7 +23,6 @@ non_tested_cars = [
GM.MALIBU,
GM.EQUINOX,
GM.BOLT_EV,
HYUNDAI.ELANTRA_GT_I30,
HYUNDAI.GENESIS_G90,
HYUNDAI.KIA_OPTIMA_H,
]
@ -91,13 +90,14 @@ routes = [
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("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("b2a38c712dcf90bd|2020-05-18--18-12-48", HYUNDAI.SONATA_LF),
CarTestRoute("fb3fd42f0baaa2f8|2022-03-30--15-25-05", HYUNDAI.TUCSON),
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("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("fa8db5869167f821|2021-06-10--22-50-10", HYUNDAI.IONIQ_PHEV),
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("5dddcbca6eb66c62|2020-07-26--13-24-19", HYUNDAI.KIA_STINGER),
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("007d5e4ad9f86d13|2021-09-30--15-09-23", HYUNDAI.KIA_K5_2021),
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("50a2212c41f65c7b|2021-05-24--16-22-06", HYUNDAI.KIA_FORTE),
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("715ac05b594e9c59|2021-06-20--16-21-07", HYUNDAI.ELANTRA_HEV_2021),
CarTestRoute("7120aa90bbc3add7|2021-08-02--07-12-31", HYUNDAI.SONATA_HYBRID),

@ -1,6 +1,7 @@
#!/usr/bin/env python3
import random
import unittest
from collections import defaultdict
from parameterized import parameterized
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}
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):
# Asserts no extra ECUs are in the fingerprinting database
for brand, config in FW_QUERY_CONFIGS.items():
for car_model, ecus in VERSIONS[brand].items():
bad_ecus = set(ecus).intersection(config.extra_ecus)
@ -80,10 +92,11 @@ class TestFwFingerprint(unittest.TestCase):
def test_fw_request_ecu_whitelist(self):
for brand, config in FW_QUERY_CONFIGS.items():
with self.subTest(brand=brand):
whitelisted_ecus = set([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])
whitelisted_ecus = {ecu for r in config.requests for ecu in r.whitelist_ecus}
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
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['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
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 SHARAN 2ND GEN: [2.5, 2.5, 0.1]
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
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 PlUG-IN HYBRID 2022: [1.6953050513611045, 1.5837614296206861, 0.12672855941458458]
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]
JEEP GRAND CHEROKEE 2019: [1.7321233388827006, 1.289689569171081, 0.15046331002097185]
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 2021: [2.6426668350384457, 2.3901492458927986, 0.16103875108816076]
TOYOTA COROLLA 2017: [3.117154369115421, 1.8438132575043773, 0.12289685869250652]
TOYOTA COROLLA HYBRID TSS2 2019: [2.3287672277252005, 1.8118712531729109, 0.2215868445753317]
TOYOTA COROLLA TSS2 2019: [2.4204464833010175, 1.9258612322678952, 0.20670411068012526]
TOYOTA COROLLA HYBRID TSS2 2019: [1.9079729107361805, 1.8118712531729109, 0.22251440891543514]
TOYOTA COROLLA TSS2 2019: [2.0742917676766712, 1.9258612322678952, 0.16888685704519352]
TOYOTA HIGHLANDER 2017: [1.8696367437248915, 1.626293990451463, 0.17485372210240796]
TOYOTA HIGHLANDER 2020: [2.022340166827233, 1.6183134804881791, 0.14592306380054457]
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 2021: KIA NIRO EV 2020
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 HYBRID 2020: HYUNDAI KONA ELECTRIC 2019
HYUNDAI KONA ELECTRIC 2022: HYUNDAI KONA ELECTRIC 2019

@ -2,7 +2,6 @@
from cereal import car
from common.conversions import Conversions as CV
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 import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config
from selfdrive.car.interfaces import CarInterfaceBase
@ -74,7 +73,6 @@ class CarInterface(CarInterfaceBase):
ret.wheelSpeedFactor = 1.035
tire_stiffness_factor = 0.5533
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):
stop_and_go = True
@ -82,7 +80,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 13.6
tire_stiffness_factor = 0.7933
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):
stop_and_go = True
@ -90,8 +87,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 13.7
tire_stiffness_factor = 0.7933
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):
stop_and_go = True
@ -99,7 +94,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 16.0
tire_stiffness_factor = 0.8
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):
# 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
tire_stiffness_factor = 0.7983
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):
stop_and_go = True
@ -117,14 +110,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 14.3
tire_stiffness_factor = 0.7933
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):
stop_and_go = True
@ -139,7 +124,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 16.0 # not optimized
tire_stiffness_factor = 0.444 # not optimized yet
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:
stop_and_go = True
@ -147,14 +131,12 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 15.5
tire_stiffness_factor = 0.444
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):
ret.wheelbase = 2.79908
ret.steerRatio = 13.3
tire_stiffness_factor = 0.444
ret.mass = 3736.8 * CV.LB_TO_KG + STD_CARGO_KG
set_lat_tune(ret.lateralTuning, LatTunes.PID_L)
elif candidate == CAR.LEXUS_CTH:
stop_and_go = True
@ -162,7 +144,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 18.6
tire_stiffness_factor = 0.517
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):
stop_and_go = True
@ -170,7 +151,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 14.7
tire_stiffness_factor = 0.444 # not optimized yet
ret.mass = 4070 * CV.LB_TO_KG + STD_CARGO_KG
set_lat_tune(ret.lateralTuning, LatTunes.PID_C)
elif candidate == CAR.PRIUS_TSS2:
stop_and_go = True
@ -178,7 +158,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 13.4 # True steerRatio from older prius
tire_stiffness_factor = 0.6371 # hand-tune
ret.mass = 3115. * CV.LB_TO_KG + STD_CARGO_KG
set_lat_tune(ret.lateralTuning, LatTunes.PID_N)
elif candidate == CAR.MIRAI:
stop_and_go = True
@ -186,7 +165,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 14.8
tire_stiffness_factor = 0.8
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):
stop_and_go = True
@ -194,7 +172,6 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 14.2
tire_stiffness_factor = 0.444
ret.mass = 4305. * CV.LB_TO_KG + STD_CARGO_KG
set_lat_tune(ret.lateralTuning, LatTunes.PID_J)
ret.centerToFront = ret.wheelbase * 0.44
@ -230,12 +207,23 @@ class CarInterface(CarInterfaceBase):
# to a negative value, so it won't matter.
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:
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:
ret.stoppingDecelRate = 0.3 # reach stopping target smoothly
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

@ -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\x8704E906023AH\xf1\x893379',
b'\xf1\x8704L906026ET\xf1\x891990',
b'\xf1\x8704L906026FP\xf1\x892012',
b'\xf1\x8704L906026GA\xf1\x892013',
b'\xf1\x8704L906026KD\xf1\x894798',
b'\xf1\x873G0906264 \xf1\x890004',
@ -562,6 +563,7 @@ FW_VERSIONS = {
(Ecu.transmission, 0x7e1, None): [
b'\xf1\x870CW300043H \xf1\x891601',
b'\xf1\x870CW300048R \xf1\x890610',
b'\xf1\x870D9300013A \xf1\x894905',
b'\xf1\x870D9300014L \xf1\x895002',
b'\xf1\x870D9300041A \xf1\x894801',
b'\xf1\x870DD300045T \xf1\x891601',
@ -579,6 +581,7 @@ FW_VERSIONS = {
],
(Ecu.eps, 0x712, None): [
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\x820522B0080803',
b'\xf1\x875Q0909144AB\xf1\x891082\xf1\x82\00521B00606A1',

@ -82,45 +82,45 @@ class Controls:
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:
# wait for one pandaState and one CAN packet
print("Waiting for CAN messages...")
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:
self.CI, self.CP = CI, CI.CP
params = Params()
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'])
self.joystick_mode = self.params.get_bool("JoystickDebugMode") or (self.CP.notCar and sm is None)
# 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
if not self.disengage_on_accelerator:
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
# read params
self.is_metric = params.get_bool("IsMetric")
self.is_ldw_enabled = params.get_bool("IsLdwEnabled")
openpilot_enabled_toggle = params.get_bool("OpenpilotEnabledToggle")
passive = params.get_bool("Passive") or not openpilot_enabled_toggle
self.is_metric = self.params.get_bool("IsMetric")
self.is_ldw_enabled = self.params.get_bool("IsLdwEnabled")
openpilot_enabled_toggle = self.params.get_bool("OpenpilotEnabledToggle")
passive = self.params.get_bool("Passive") or not openpilot_enabled_toggle
# detect sound card presence and ensure successful init
sounds_available = HARDWARE.get_sound_card_online()
@ -139,15 +139,15 @@ class Controls:
# Write CarParams for radard
cp_bytes = self.CP.to_bytes()
params.put("CarParams", cp_bytes)
self.params.put("CarParams", cp_bytes)
put_nonblocking("CarParamsCache", cp_bytes)
put_nonblocking("CarParamsPersistent", cp_bytes)
# cleanup old params
if not self.CP.experimentalLongitudinalAvailable:
params.remove("ExperimentalLongitudinalEnabled")
self.params.remove("ExperimentalLongitudinalEnabled")
if not self.CP.openpilotLongitudinalControl:
params.remove("EndToEndLong")
self.params.remove("EndToEndLong")
self.CC = car.CarControl.new_message()
self.CS_prev = car.CarState.new_message()
@ -583,9 +583,9 @@ class Controls:
"""Given the state, this function returns a CarControl packet"""
# Update VehicleModel
params = self.sm['liveParameters']
x = max(params.stiffnessFactor, 0.1)
sr = max(params.steerRatio, 0.1)
lp = self.sm['liveParameters']
x = max(lp.stiffnessFactor, 0.1)
sr = max(lp.steerRatio, 0.1)
self.VM.update_params(x, sr)
# Update Torque Params
@ -628,7 +628,7 @@ class Controls:
lat_plan.psis,
lat_plan.curvatures,
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.desired_curvature_rate, self.sm['liveLocationKalman'])
else:
@ -768,10 +768,10 @@ class Controls:
(self.state == State.softDisabling)
# Curvature & Steering angle
params = self.sm['liveParameters']
lp = self.sm['liveParameters']
steer_angle_without_offset = math.radians(CS.steeringAngleDeg - params.angleOffsetDeg)
curvature = -self.VM.calc_curvature(steer_angle_without_offset, CS.vEgo, params.roll)
steer_angle_without_offset = math.radians(CS.steeringAngleDeg - lp.angleOffsetDeg)
curvature = -self.VM.calc_curvature(steer_angle_without_offset, CS.vEgo, lp.roll)
# controlsState
dat = messaging.new_message('controlsState')
@ -856,6 +856,8 @@ class Controls:
start_time = sec_since_boot()
self.prof.checkpoint("Ratekeeper", ignore=True)
self.is_metric = self.params.get_bool("IsMetric")
# Sample data from sockets and get a carState
CS = self.data_sample()
cloudlog.timestamp("Data sampled")

@ -13,6 +13,7 @@ V_CRUISE_MIN = 8 # kph
V_CRUISE_ENABLE_MIN = 40 # kph
V_CRUISE_INITIAL = 255 # kph
MIN_SPEED = 1.0
LAT_MPC_N = 16
LON_MPC_N = 32
CONTROL_N = 17
@ -102,7 +103,7 @@ def get_lag_adjusted_curvature(CP, v_ego, psis, curvatures, curvature_rates):
psis = [0.0]*CONTROL_N
curvatures = [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
delay = CP.steerActuatorDelay + .2

@ -811,7 +811,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, AlertCallbackType]]] = {
ET.NO_ENTRY: NoEntryAlert("Cruise Faulted"),
},
EventName.gmAccFaultedTemp: {
EventName.accFaultedTemp: {
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
# move it at all, this is compensated for too.
LOW_SPEED_FACTOR = 100
LOW_SPEED_FACTOR = 200
class LatControlTorque(LatControl):

@ -4,7 +4,7 @@ from common.numpy_fast import interp
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 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
import cereal.messaging as messaging
from cereal import log
@ -23,8 +23,6 @@ LATERAL_JERK_COST = 0.05
# speed lateral control is stable on all cars
STEERING_RATE_COST = 800.0
MIN_SPEED = .3
class LateralPlanner:
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]
constraint_cost_weights = [LIMIT_COST, LIMIT_COST, LIMIT_COST, DANGER_ZONE_COST]
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]
else:
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 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:
cloudlog.info("FCW triggered")

@ -94,6 +94,9 @@ class TestStartup(unittest.TestCase):
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.pandaStates[0].pandaType = log.PandaState.PandaType.uno
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)
else:
# Live mode
print(f"Waiting for messages on bus {bus}")
try:
while 1:
can_recv = messaging.drain_sock(logcan)
@ -89,14 +90,17 @@ if __name__ == "__main__":
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
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("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")
args = parser.parse_args()
init_lr, new_lr = None, None
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:
new_lr = logreader_from_route_or_segment(args.comp)

@ -19,7 +19,7 @@ if __name__ == "__main__":
for m in msgs:
ts[s].append(m.logMonoTime / 1e6)
if len(ts[s]):
if len(ts[s]) > 2:
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}")
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
MAX_ALLOWED_SPREAD = np.radians(2)
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
PITCH_LIMITS = np.array([-0.09074112085129739, 0.14907572052989657])
@ -67,6 +68,7 @@ class Calibrator:
calibration_params = params.get("CalibrationParams")
self.wide_camera = params.get_bool('WideCameraOnly')
rpy_init = RPY_INIT
wide_from_device_euler = WIDE_FROM_DEVICE_EULER_INIT
valid_blocks = 0
if param_put and calibration_params:
@ -74,24 +76,34 @@ class Calibrator:
msg = log.Event.from_bytes(calibration_params)
rpy_init = np.array(msg.liveCalibration.rpyCalib)
valid_blocks = msg.liveCalibration.validBlocks
wide_from_device_euler = np.array(msg.liveCalibration.wideFromDeviceEuler)
except Exception:
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()
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():
self.rpy = RPY_INIT.copy()
else:
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:
self.valid_blocks = 0
else:
self.valid_blocks = valid_blocks
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.block_idx = 0
@ -113,6 +125,7 @@ class Calibrator:
def update_status(self) -> None:
valid_idxs = self.get_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]
self.rpy = np.mean(rpys, axis=0)
max_rpy_calib = np.array(np.max(rpys, axis=0))
@ -146,7 +159,10 @@ class Calibrator:
else:
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)
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 = 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
if self.idx == 0:
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.rpyCalib = smooth_rpy.tolist()
liveCalibration.rpyCalibSpread = self.calib_spread.tolist()
liveCalibration.wideFromDeviceEuler = self.wide_from_device_euler.tolist()
if self.not_car:
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)
new_rpy = calibrator.handle_cam_odom(sm['cameraOdometry'].trans,
sm['cameraOdometry'].rot,
sm['cameraOdometry'].wideFromDeviceEuler,
sm['cameraOdometry'].transStd)
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;
// 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 edata = (name == "driverEncodeData") ? event.getDriverEncodeData() :
((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/preprocessing.py",
"#tinygrad_repo/extra/onnx.py",
"#tinygrad_repo/extra/thneed.py",
"#tinygrad_repo/extra/utils.py",
"#tinygrad_repo/tinygrad/llops/ops_gpu.py",
"#tinygrad_repo/tinygrad/llops/ops_opencl.py",

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

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

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

@ -62,9 +62,9 @@ ModelOutput* model_eval_frame(ModelState* s, VisionBuf* buf, VisionBuf* wbuf,
// Model decides when action is completed
// so desire input is just a pulse triggered on rising edge
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 {
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];
}
@ -363,14 +363,19 @@ void posenet_publish(PubMaster &pm, uint32_t vipc_frame_id, uint32_t vipc_droppe
MessageBuilder msg;
const auto &v_mean = net_outputs.pose.velocity_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 &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();
posenetd.setTrans({v_mean.x, v_mean.y, v_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.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.setFrameId(vipc_frame_id);

@ -28,12 +28,13 @@ constexpr int BLINKER_LEN = 6;
constexpr int META_STRIDE = 7;
constexpr int PLAN_MHP_N = 5;
constexpr int STOP_LINE_MHP_N = 3;
constexpr int LEAD_MHP_N = 2;
constexpr int LEAD_TRAJ_LEN = 6;
constexpr int LEAD_PRED_DIM = 4;
constexpr int LEAD_MHP_SELECTION = 3;
// Padding to get output shape as multiple of 4
constexpr int PAD_SIZE = 2;
struct ModelOutputXYZ {
float x;
@ -151,36 +152,6 @@ struct ModelOutputLeads {
};
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 {
ModelOutputXYZ velocity_mean;
@ -190,6 +161,12 @@ struct ModelOutputPose {
};
static_assert(sizeof(ModelOutputPose) == sizeof(ModelOutputXYZ)*4);
struct ModelOutputWideFromDeviceEuler {
ModelOutputXYZ mean;
ModelOutputXYZ std;
};
static_assert(sizeof(ModelOutputWideFromDeviceEuler) == sizeof(ModelOutputXYZ)*2);
struct ModelOutputDisengageProb {
float gas_disengage;
float brake_disengage;
@ -245,9 +222,9 @@ struct ModelOutput {
const ModelOutputLaneLines lane_lines;
const ModelOutputRoadEdges road_edges;
const ModelOutputLeads leads;
const ModelOutputStopLines stop_lines;
const ModelOutputMeta meta;
const ModelOutputPose pose;
const ModelOutputWideFromDeviceEuler wide_from_device_euler;
};
constexpr int OUTPUT_SIZE = sizeof(ModelOutput) / sizeof(float);
@ -257,7 +234,7 @@ constexpr int OUTPUT_SIZE = sizeof(ModelOutput) / sizeof(float);
#else
constexpr int TEMPORAL_SIZE = 0;
#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
struct ModelState {

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

@ -29,10 +29,11 @@ class DRIVER_MONITOR_SETTINGS():
self._FACE_THRESHOLD = 0.7
self._EYE_THRESHOLD = 0.65
self._SG_THRESHOLD = 0.9
self._BLINK_THRESHOLD = 0.87
self._BLINK_THRESHOLD = 0.895
self._EE_THRESH11 = 0.75
self._EE_THRESH12 = 3.25
self._EE_THRESH11 = 0.275
self._EE_THRESH12 = 5.5
self._EE_MAX_OFFSET1 = 0.06
self._EE_THRESH21 = 0.01
self._EE_THRESH22 = 0.35
@ -204,14 +205,14 @@ class DriverStatus():
distracted_types.append(DistractedType.DISTRACTED_BLINK)
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:
ee1_dist = self.eev1 > self.settings._EE_THRESH11
if self.ee2_calibrated:
ee2_dist = self.eev2 < self.ee2_offseter.filtered_stat.M * self.settings._EE_THRESH22
else:
ee2_dist = self.eev2 < self.settings._EE_THRESH21
if ee1_dist or ee2_dist:
# if self.ee2_calibrated:
# ee2_dist = self.eev2 < self.ee2_offseter.filtered_stat.M * self.settings._EE_THRESH22
# else:
# ee2_dist = self.eev2 < self.settings._EE_THRESH21
if ee1_dist:
distracted_types.append(DistractedType.DISTRACTED_E2E)
return distracted_types
@ -257,12 +258,11 @@ class DriverStatus():
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.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.distracted_types = self._get_distracted_types()
self.driver_distracted = (DistractedType.DISTRACTED_POSE in self.distracted_types or
DistractedType.DISTRACTED_BLINK in self.distracted_types) and \
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 \
driver_data.faceProb > self.settings._FACE_THRESHOLD and self.pose.low_std
self.driver_distraction_filter.update(self.driver_distracted)

@ -87,16 +87,24 @@ def try_setup_logs(diag, log_types):
else:
raise Exception(f"setup logs failed, {log_types=}")
def mmcli(cmd: str) -> None:
def at_cmd(cmd: str) -> None:
for _ in range(5):
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
except subprocess.CalledProcessError:
cloudlog.exception("rawgps.mmcli_command_failed")
else:
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):
# enable OEMDRE in the NV
# TODO: it has to reboot for this to take effect
@ -108,11 +116,16 @@ def setup_quectel(diag: ModemDiag):
setup_logs(diag, LOG_TYPES)
if gps_enabled():
at_cmd("AT+QGPSEND")
# 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
mmcli("--command='AT+QGPSCFG=\"autogps\",0'")
mmcli("--location-enable-gps-raw --location-enable-gps-nmea")
at_cmd("AT+QGPSCFG=\"autogps\",0")
at_cmd("AT+QGPSCFG=\"outport\",\"usbnmea\"")
at_cmd("AT+QGPS=1")
# enable OEMDRE mode
DIAG_SUBSYS_CMD_F = 75
@ -134,7 +147,9 @@ def setup_quectel(diag: ModemDiag):
))
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, [])
@ -156,7 +171,7 @@ def main() -> NoReturn:
# wait for ModemManager to come up
cloudlog.warning("waiting for modem to come up")
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:
break
time.sleep(0.1)

@ -22,7 +22,7 @@ from tools.lib.logreader import LogReader
TEST_ROUTE = "4cf7a6ad03080c90|2021-09-29--13-46-36"
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"))
@ -149,9 +149,9 @@ if __name__ == "__main__":
# load logs
lr = list(LogReader(get_url(TEST_ROUTE, SEGMENT)))
frs = {
'roadCameraState': FrameReader(get_url(TEST_ROUTE, SEGMENT, log_type="fcamera")),
'driverCameraState': FrameReader(get_url(TEST_ROUTE, SEGMENT, log_type="dcamera")),
'wideRoadCameraState': FrameReader(get_url(TEST_ROUTE, SEGMENT, log_type="ecamera"))
'roadCameraState': FrameReader(get_url(TEST_ROUTE, SEGMENT, log_type="fcamera"), readahead=True),
'driverCameraState': FrameReader(get_url(TEST_ROUTE, SEGMENT, log_type="dcamera"), readahead=True),
'wideRoadCameraState': FrameReader(get_url(TEST_ROUTE, SEGMENT, log_type="ecamera"), readahead=True)
}
# run replay

@ -1 +1 @@
bfb0a2a52212d2aa1619d999aaae97fa7f7ff788
d2f1711fd58d4f2c25b81bd332270da60ff9636d

@ -1 +1 @@
e5a86c14e2318f2dd218b3985cdbea6f875f7d83
8f2919ba4d8509432e93ff0a44f951254c1ff3fe

@ -18,7 +18,7 @@ from tools.lib.logreader import LogReader
source_segments = [
("BODY", "937ccb7243511b65|2022-05-24--16-03-09--1"), # COMMA.BODY
("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)
("TOYOTA2", "0982d79ebb0de295|2021-01-03--20-03-36--6"), # TOYOTA.RAV4 (LQR)
("TOYOTA3", "f7d7e3538cda1a2a|2021-08-16--08-55-34--6"), # TOYOTA.COROLLA_TSS2
@ -40,7 +40,7 @@ source_segments = [
segments = [
("BODY", "regenFA002A80700|2022-09-27--15-37-02--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"),
("TOYOTA2", "regenEA3950D7F22|2022-09-27--15-43-24--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 checkout $GIT_COMMIT
git clean -xdff
git submodule sync
git submodule update --init --recursive
git submodule foreach --recursive "git reset --hard && git clean -xdff"

@ -120,8 +120,8 @@ class TestOnroad(unittest.TestCase):
if "DEBUG" in os.environ:
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)
print(segs[-1])
cls.lr = list(LogReader(os.path.join(segs[-1], "rlog")))
print(segs[-2])
cls.lr = list(LogReader(os.path.join(segs[-2], "rlog")))
return
# 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.]
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):
proclogs = [m for m in self.lr if m.which() == 'procLog']
self.assertGreater(len(proclogs), service_list['procLog'].frequency * 45, "insufficient samples")

@ -1,6 +1,8 @@
#!/usr/bin/env python3
from functools import lru_cache
import sys
import subprocess
from tqdm import tqdm
from azure.storage.blob import BlockBlobService # pylint: disable=import-error
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 = [
(_DATA_ACCOUNT_PRODUCTION, _DATA_BUCKET_PRODUCTION),
(_DATA_ACCOUNT_PRODUCTION, "preserve"),
(_DATA_ACCOUNT_CI, "commadataci"),
]
@lru_cache
def get_azure_keys():
dest_key = azureutil.get_user_token(_DATA_ACCOUNT_CI, "openpilotci")
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([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):
failed_routes.append(r)

@ -1,11 +1,9 @@
#include "selfdrive/ui/qt/home.h"
#include <QDateTime>
#include <QHBoxLayout>
#include <QMouseEvent>
#include <QVBoxLayout>
#include "common/params.h"
#include "selfdrive/ui/qt/util.h"
#include "selfdrive/ui/qt/widgets/drive_stats.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->setSpacing(16);
date = new QLabel();
header_layout->addWidget(date, 1, Qt::AlignHCenter | Qt::AlignLeft);
update_notif = new QPushButton(tr("UPDATE"));
update_notif->setVisible(false);
update_notif->setStyleSheet("background-color: #364DEF;");
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->setVisible(false);
alert_notif->setStyleSheet("background-color: #E22C2C;");
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);
@ -184,9 +180,7 @@ void OffroadHome::hideEvent(QHideEvent *event) {
}
void OffroadHome::refresh() {
QString locale_name = QString(uiState()->language).replace("main_", "");
QString dateString = QLocale(locale_name).toString(QDateTime::currentDateTime(), "dddd, MMMM d");
date->setText(dateString);
version->setText(getBrand() + " " + QString::fromStdString(params.get("UpdaterCurrentDescription")));
bool updateAvailable = update_widget->refresh();
int alerts = alerts_widget->refresh();

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

@ -12,11 +12,11 @@ DriverViewWindow::DriverViewWindow(QWidget* parent) : QWidget(parent) {
layout = new QStackedLayout(this);
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);
scene = new DriverViewScene(this);
connect(cameraView, &CameraViewWidget::vipcThreadFrameReceived, scene, &DriverViewScene::frameUpdated);
connect(cameraView, &CameraWidget::vipcThreadFrameReceived, scene, &DriverViewScene::frameUpdated);
layout->addWidget(scene);
layout->setCurrentWidget(scene);
}

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

@ -145,11 +145,11 @@ void SoftwarePanel::updateLabels() {
targetBranchBtn->setValue(QString::fromStdString(params.get("UpdaterTargetBranch")));
// 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")));
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")));
update();

@ -368,7 +368,7 @@ void WifiManager::updateGsmSettings(bool roaming, QString apn, bool metered) {
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) {
qWarning() << "Changing connection.metered to" << meteredInt;
settings["connection"]["metered"] = meteredInt;

@ -18,7 +18,7 @@ OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent) {
stacked_layout->setStackingMode(QStackedLayout::StackAll);
main_layout->addLayout(stacked_layout);
nvg = new NvgWindow(VISION_STREAM_ROAD, this);
nvg = new AnnotatedCameraWidget(VISION_STREAM_ROAD, this);
QWidget * split_wrapper = new QWidget;
split = new QHBoxLayout(split_wrapper);
@ -27,7 +27,7 @@ OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent) {
split->addWidget(nvg);
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);
}
@ -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});
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 SubMaster &sm = *(s.sm);
@ -232,13 +233,13 @@ void NvgWindow::updateState(const UIState &s) {
}
if (s.scene.calibration_valid) {
CameraViewWidget::updateCalibration(s.scene.view_from_calib);
CameraWidget::updateCalibration(s.scene.view_from_calib);
} else {
CameraViewWidget::updateCalibration(DEFAULT_CALIBRATION);
CameraWidget::updateCalibration(DEFAULT_CALIBRATION);
}
}
void NvgWindow::drawHud(QPainter &p) {
void AnnotatedCameraWidget::drawHud(QPainter &p) {
p.save();
// Header gradient
@ -400,7 +401,11 @@ void NvgWindow::drawHud(QPainter &p) {
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);
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);
}
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.setBrush(bg);
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() {
CameraViewWidget::initializeGL();
void AnnotatedCameraWidget::initializeGL() {
CameraWidget::initializeGL();
qInfo() << "OpenGL version:" << QString((const char*)glGetString(GL_VERSION));
qInfo() << "OpenGL vendor:" << QString((const char*)glGetString(GL_VENDOR));
qInfo() << "OpenGL renderer:" << QString((const char*)glGetString(GL_RENDERER));
@ -428,8 +433,8 @@ void NvgWindow::initializeGL() {
setBackgroundColor(bg_colors[STATUS_DISENGAGED]);
}
void NvgWindow::updateFrameMat() {
CameraViewWidget::updateFrameMat();
void AnnotatedCameraWidget::updateFrameMat() {
CameraWidget::updateFrameMat();
UIState *s = uiState();
int w = width(), h = height();
@ -446,7 +451,7 @@ void NvgWindow::updateFrameMat() {
.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();
const UIScene &scene = s->scene;
@ -505,7 +510,7 @@ void NvgWindow::drawLaneLines(QPainter &painter, const UIState *s) {
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();
const float speedBuff = 10.;
@ -541,11 +546,13 @@ void NvgWindow::drawLead(QPainter &painter, const cereal::ModelDataV2::LeadDataV
painter.restore();
}
void NvgWindow::paintGL() {
void AnnotatedCameraWidget::paintGL() {
const double start_draw_t = millis_since_boot();
UIState *s = uiState();
const cereal::ModelDataV2::Reader &model = (*s->sm)["modelV2"].getModelV2();
CameraViewWidget::setFrameId(model.getFrameId());
CameraViewWidget::paintGL();
CameraWidget::setFrameId(model.getFrameId());
CameraWidget::paintGL();
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
@ -575,10 +582,16 @@ void NvgWindow::paintGL() {
LOGW("slow frame rate: %.2f fps", fps);
}
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) {
CameraViewWidget::showEvent(event);
void AnnotatedCameraWidget::showEvent(QShowEvent *event) {
CameraWidget::showEvent(event);
ui_update_params(uiState());
prev_draw_t = millis_since_boot();

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

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

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

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

@ -23,13 +23,13 @@
const int FRAME_BUFFER_SIZE = 5;
static_assert(FRAME_BUFFER_SIZE <= YUV_BUFFER_COUNT);
class CameraViewWidget : public QOpenGLWidget, protected QOpenGLFunctions {
class CameraWidget : public QOpenGLWidget, protected QOpenGLFunctions {
Q_OBJECT
public:
using QOpenGLWidget::QOpenGLWidget;
explicit CameraViewWidget(std::string stream_name, VisionStreamType stream_type, bool zoom, QWidget* parent = nullptr);
~CameraViewWidget();
explicit CameraWidget(std::string stream_name, VisionStreamType stream_type, bool zoom, QWidget* parent = nullptr);
~CameraWidget();
void setStreamType(VisionStreamType type) { stream_type = type; }
void setBackgroundColor(const QColor &color) { bg = color; }
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);
// value next to control button
value = new QLabel();
value = new ElidedLabel();
value->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
value->setStyleSheet("color: #aaaaaa");
hlayout->addWidget(value);
@ -70,7 +70,7 @@ AbstractControl::AbstractControl(const QString &title, const QString &desc, cons
}
void AbstractControl::hideEvent(QHideEvent *e) {
if(description != nullptr) {
if (description != nullptr) {
description->hide();
}
}

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

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

File diff suppressed because it is too large Load Diff

@ -67,6 +67,29 @@
<translation type="unfinished"></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></translation>
</message>
<message>
<source>SPEED</source>
<translation></translation>
</message>
<message>
<source>LIMIT</source>
<translation></translation>
</message>
</context>
<context>
<name>ConfirmationDialog</name>
<message>
@ -406,29 +429,6 @@ location set</source>
<translation></translation>
</message>
</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>
<name>OffroadHome</name>
<message>

@ -60,11 +60,34 @@
</message>
<message>
<source>Cellular Metered</source>
<translation type="unfinished"></translation>
<translation> </translation>
</message>
<message>
<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>
</context>
<context>
@ -406,29 +429,6 @@ location set</source>
<translation> </translation>
</message>
</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>
<name>OffroadHome</name>
<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>
</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>LIMITE</translation>
</message>
<message>
<source>SPEED</source>
<translation>MAX</translation>
</message>
<message>
<source>LIMIT</source>
<translation>VELO</translation>
</message>
</context>
<context>
<name>ConfirmationDialog</name>
<message>
@ -407,29 +430,6 @@ trabalho definido</translation>
<translation>Senha incorreta</translation>
</message>
</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>
<name>OffroadHome</name>
<message>

File diff suppressed because it is too large Load Diff

@ -67,6 +67,29 @@
<translation type="unfinished"></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></translation>
</message>
<message>
<source>SPEED</source>
<translation>SPEED</translation>
</message>
<message>
<source>LIMIT</source>
<translation>LIMIT</translation>
</message>
</context>
<context>
<name>ConfirmationDialog</name>
<message>
@ -404,29 +427,6 @@ location set</source>
<translation></translation>
</message>
</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>
<name>OffroadHome</name>
<message>

@ -67,6 +67,29 @@
<translation type="unfinished"></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></translation>
</message>
<message>
<source>SPEED</source>
<translation></translation>
</message>
<message>
<source>LIMIT</source>
<translation></translation>
</message>
</context>
<context>
<name>ConfirmationDialog</name>
<message>
@ -406,29 +429,6 @@ location set</source>
<translation></translation>
</message>
</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>
<name>OffroadHome</name>
<message>

@ -163,7 +163,8 @@ static void update_state(UIState *s) {
scene.longitudinal_control = sm["carParams"].getCarParams().getOpenpilotLongitudinalControl();
}
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;
}

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

@ -280,17 +280,25 @@ class Updater:
# Write out current and new version info
def get_description(basedir: str) -> str:
if not os.path.exists(basedir):
return ""
version = ""
branch = ""
commit = ""
commit_date = ""
try:
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:
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:
pass
return f"{version} / {branch} / {commit[:7]}"
cloudlog.exception("updater.get_description")
return f"{version} / {branch} / {commit} / {commit_date}"
self.params.put("UpdaterCurrentDescription", get_description(BASEDIR))
self.params.put("UpdaterCurrentReleaseNotes", parse_release_notes(BASEDIR))
self.params.put("UpdaterNewDescription", get_description(FINALIZED))
@ -365,6 +373,7 @@ class Updater:
["git", "checkout", "--force", "--no-recurse-submodules", "-B", branch, "FETCH_HEAD"],
["git", "reset", "--hard"],
["git", "clean", "-xdff"],
["git", "submodule", "sync"],
["git", "submodule", "init"],
["git", "submodule", "update"],
]

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

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

@ -6,7 +6,6 @@ openpilot is developed and tested on **Ubuntu 20.04**, which is the primary deve
## Setup your PC
First, clone openpilot:
``` bash
cd ~
@ -26,10 +25,10 @@ tools/ubuntu_setup.sh
tools/mac_setup.sh
```
Activate a shell with the install Python dependencies:
Activate a shell with the Python dependencies installed:
``` bash
cd openpilot && pipenv shell
cd openpilot && poetry shell
```
Build openpilot with this command:

@ -3,3 +3,5 @@ moc_*
_cabana
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