Merge branch 'master' into mqb-long

# Conflicts:
#	opendbc
#	panda
#	selfdrive/car/volkswagen/carstate.py
#	selfdrive/car/volkswagen/interface.py
pull/22963/head
Jason Young 3 years ago
commit a876bdd090
  1. 110
      .github/workflows/selfdrive_tests.yaml
  2. 15
      .github/workflows/tools_tests.yaml
  3. 1
      .gitignore
  4. 4
      .lfsconfig
  5. 8
      .pre-commit-config.yaml
  6. 80
      Dockerfile.openpilot_base
  7. 8
      Pipfile
  8. 1179
      Pipfile.lock
  9. 25
      RELEASES.md
  10. 10
      SConstruct
  11. 2
      cereal
  12. 2
      common/ffi_wrapper.py
  13. 15
      common/file_helpers.py
  14. 2
      common/profiler.py
  15. 4
      common/realtime.py
  16. 2
      common/spinner.py
  17. 2
      common/tests/test_file_helpers.py
  18. 2
      common/timeout.py
  19. 12
      common/transformations/camera.py
  20. 6
      common/transformations/model.py
  21. 9
      docs/CARS.md
  22. 52
      docs/CONTRIBUTING.md
  23. BIN
      docs/_static/favicon.ico
  24. BIN
      docs/_static/logo.png
  25. 2
      docs/_static/robots.txt
  26. 105
      docs/c_docs.rst
  27. 95
      docs/conf.py
  28. 1
      docs/docker/Dockerfile
  29. 9
      docs/index.md
  30. 2
      launch_env.sh
  31. 2
      models/supercombo.dlc
  32. 4
      models/supercombo.onnx
  33. 2
      opendbc
  34. 2
      panda
  35. 2
      release/files_common
  36. 0
      selfdrive/assets/sounds/disengage.wav
  37. 0
      selfdrive/assets/sounds/engage.wav
  38. 0
      selfdrive/assets/sounds/prompt.wav
  39. 0
      selfdrive/assets/sounds/prompt_distracted.wav
  40. 0
      selfdrive/assets/sounds/refuse.wav
  41. BIN
      selfdrive/assets/sounds/warning_immediate.wav
  42. 0
      selfdrive/assets/sounds/warning_soft.wav
  43. 117
      selfdrive/athena/athenad.py
  44. 6
      selfdrive/athena/manage_athenad.py
  45. 2
      selfdrive/athena/registration.py
  46. 22
      selfdrive/athena/tests/helpers.py
  47. 34
      selfdrive/athena/tests/test_athenad.py
  48. 48
      selfdrive/boardd/boardd.cc
  49. 4
      selfdrive/boardd/panda.cc
  50. 2
      selfdrive/boardd/panda.h
  51. 2
      selfdrive/boardd/tests/test_boardd_loopback.py
  52. 11
      selfdrive/camerad/cameras/camera_common.cc
  53. 3
      selfdrive/camerad/cameras/camera_common.h
  54. 45
      selfdrive/camerad/cameras/camera_qcom.cc
  55. 1
      selfdrive/camerad/cameras/camera_qcom.h
  56. 7
      selfdrive/camerad/cameras/camera_qcom2.cc
  57. 4
      selfdrive/camerad/cameras/camera_replay.cc
  58. 4
      selfdrive/camerad/cameras/camera_webcam.cc
  59. 8
      selfdrive/camerad/imgproc/utils.cc
  60. 8
      selfdrive/camerad/imgproc/utils.h
  61. 4
      selfdrive/camerad/main.cc
  62. 2
      selfdrive/camerad/test/test_camerad.py
  63. 12
      selfdrive/car/car_helpers.py
  64. 9
      selfdrive/car/chrysler/carcontroller.py
  65. 2
      selfdrive/car/chrysler/carstate.py
  66. 2
      selfdrive/car/chrysler/chryslercan.py
  67. 6
      selfdrive/car/chrysler/interface.py
  68. 4
      selfdrive/car/fingerprints.py
  69. 6
      selfdrive/car/ford/carcontroller.py
  70. 2
      selfdrive/car/ford/carstate.py
  71. 2
      selfdrive/car/ford/fordcan.py
  72. 6
      selfdrive/car/ford/interface.py
  73. 23
      selfdrive/car/fw_versions.py
  74. 32
      selfdrive/car/gm/carcontroller.py
  75. 5
      selfdrive/car/gm/carstate.py
  76. 20
      selfdrive/car/gm/interface.py
  77. 1
      selfdrive/car/gm/radar_interface.py
  78. 41
      selfdrive/car/honda/carcontroller.py
  79. 12
      selfdrive/car/honda/carstate.py
  80. 4
      selfdrive/car/honda/hondacan.py
  81. 30
      selfdrive/car/honda/interface.py
  82. 112
      selfdrive/car/honda/values.py
  83. 18
      selfdrive/car/hyundai/carcontroller.py
  84. 4
      selfdrive/car/hyundai/hyundaican.py
  85. 28
      selfdrive/car/hyundai/interface.py
  86. 2
      selfdrive/car/hyundai/radar_interface.py
  87. 59
      selfdrive/car/hyundai/values.py
  88. 33
      selfdrive/car/interfaces.py
  89. 6
      selfdrive/car/mazda/carcontroller.py
  90. 8
      selfdrive/car/mazda/interface.py
  91. 15
      selfdrive/car/mazda/values.py
  92. 3
      selfdrive/car/mock/interface.py
  93. 11
      selfdrive/car/nissan/carcontroller.py
  94. 22
      selfdrive/car/nissan/carstate.py
  95. 15
      selfdrive/car/nissan/interface.py
  96. 23
      selfdrive/car/subaru/carcontroller.py
  97. 43
      selfdrive/car/subaru/carstate.py
  98. 21
      selfdrive/car/subaru/interface.py
  99. 8
      selfdrive/car/subaru/subarucan.py
  100. 372
      selfdrive/car/subaru/values.py
  101. Some files were not shown because too many files have changed in this diff Show More

@ -69,52 +69,62 @@ jobs:
rm -rf /tmp/scons_cache/* && \
scons -j$(nproc) --cache-populate"
#build_mac:
# name: build macos
# runs-on: macos-10.15
# timeout-minutes: 60
# steps:
# - uses: actions/checkout@v2
# with:
# submodules: true
# - name: Determine pre-existing Homebrew packages
# if: steps.dependency-cache.outputs.cache-hit != 'true'
# run: |
# echo 'EXISTING_CELLAR<<EOF' >> $GITHUB_ENV
# ls -1 /usr/local/Cellar >> $GITHUB_ENV
# echo 'EOF' >> $GITHUB_ENV
# - name: Cache dependencies
# id: dependency-cache
# uses: actions/cache@v2
# with:
# path: |
# ~/.pyenv
# ~/Library/Caches/pip
# ~/Library/Caches/pipenv
# /usr/local/Cellar
# ~/github_brew_cache_entries.txt
# key: macos-cache-${{ hashFiles('tools/mac_setup.sh') }}
# - name: Brew link restored dependencies
# if: steps.dependency-cache.outputs.cache-hit == 'true'
# run: |
# while read pkg; do
# brew link --force "$pkg" # `--force` for keg-only packages
# done < ~/github_brew_cache_entries.txt
# - name: Install dependencies
# run: ./tools/mac_setup.sh
# - name: Build openpilot
# run: eval "$(pyenv init -)" && scons -j$(nproc)
# - name: Remove pre-existing Homebrew packages for caching
# if: steps.dependency-cache.outputs.cache-hit != 'true'
# run: |
# cd /usr/local/Cellar
# new_cellar=$(ls -1)
# comm -12 <(echo "$EXISTING_CELLAR") <(echo "$new_cellar") | while read pkg; do
# if [[ $pkg != "zstd" ]]; then # caching step needs zstd
# rm -rf "$pkg"
# fi
# done
# comm -13 <(echo "$EXISTING_CELLAR") <(echo "$new_cellar") | tee ~/github_brew_cache_entries.txt
build_mac:
name: build macos
runs-on: macos-latest
timeout-minutes: 60
steps:
- uses: actions/checkout@v2
with:
submodules: true
- name: Determine pre-existing Homebrew packages
if: steps.dependency-cache.outputs.cache-hit != 'true'
run: |
echo 'EXISTING_CELLAR<<EOF' >> $GITHUB_ENV
ls -1 /usr/local/Cellar >> $GITHUB_ENV
echo 'EOF' >> $GITHUB_ENV
- name: Cache dependencies
id: dependency-cache
uses: actions/cache@v2
with:
path: |
~/.pyenv
~/.local/share/virtualenvs/
/usr/local/Cellar
~/github_brew_cache_entries.txt
/tmp/scons_cache
key: macos-${{ hashFiles('tools/mac_setup.sh', 'update_requirements.sh', 'Pipfile*') }}
restore-keys: macos-
- name: Brew link restored dependencies
run: |
if [ -f ~/github_brew_cache_entries.txt ]; then
while read pkg; do
brew link --force "$pkg" # `--force` for keg-only packages
done < ~/github_brew_cache_entries.txt
else
echo "Cache entries not found"
fi
- name: Install dependencies
run: ./tools/mac_setup.sh
- name: Build openpilot
run: |
source tools/openpilot_env.sh
pipenv run selfdrive/manager/build.py
# cleanup scons cache
rm -rf /tmp/scons_cache/
pipenv run scons -j$(nproc) --cache-populate
- name: Remove pre-existing Homebrew packages for caching
if: steps.dependency-cache.outputs.cache-hit != 'true'
run: |
cd /usr/local/Cellar
new_cellar=$(ls -1)
comm -12 <(echo "$EXISTING_CELLAR") <(echo "$new_cellar") | while read pkg; do
if [[ $pkg != "zstd" ]]; then # caching step needs zstd
rm -rf "$pkg"
fi
done
comm -13 <(echo "$EXISTING_CELLAR") <(echo "$new_cellar") | tee ~/github_brew_cache_entries.txt
build_webcam:
name: build webcam
@ -246,6 +256,7 @@ jobs:
$UNIT_TEST selfdrive/locationd && \
$UNIT_TEST selfdrive/athena && \
$UNIT_TEST selfdrive/thermald && \
$UNIT_TEST selfdrive/hardware/tici && \
$UNIT_TEST tools/lib/tests && \
./selfdrive/boardd/tests/test_boardd_usbprotocol && \
./selfdrive/common/tests/test_util && \
@ -350,11 +361,12 @@ jobs:
name: longitudinal
path: selfdrive/test/longitudinal_maneuvers/out/longitudinal/
test_car_models:
name: car models
test_cars:
name: cars
runs-on: ubuntu-20.04
timeout-minutes: 50
strategy:
fail-fast: false
matrix:
job: [0, 1, 2, 3]
steps:
@ -384,7 +396,7 @@ jobs:
- name: Test car models
run: |
${{ env.RUN }} "scons -j$(nproc) --test && \
FILEREADER_CACHE=1 coverage run selfdrive/test/test_models.py && \
FILEREADER_CACHE=1 pytest selfdrive/test/test_models.py && \
chmod -R 777 /tmp/comma_download_cache"
env:
NUM_JOBS: 4

@ -45,7 +45,20 @@ jobs:
- uses: actions/checkout@v2
with:
submodules: true
lfs: true
# HACK: cache LFS objects since they count against our quota
# https://github.com/actions/checkout/issues/165#issuecomment-657673315
- name: Create LFS file list
run: git lfs ls-files -l | cut -d' ' -f1 | sort > .lfs-assets-id
- name: Restore LFS cache
uses: actions/cache@v2
id: lfs-cache
with:
path: .git/lfs
key: ${{ runner.os }}-lfs-${{ hashFiles('.lfs-assets-id') }}
- name: Git LFS Pull
run: git lfs pull
- name: Build Docker image
run: |
eval "$BUILD"

1
.gitignore vendored

@ -1,4 +1,5 @@
venv/
.env
.clang-format
.DS_Store
.tags

@ -0,0 +1,4 @@
[lfs]
url = https://gitlab.com/commaai/openpilot-lfs.git/info/lfs
pushurl = ssh://git@gitlab.com/commaai/openpilot-lfs.git
locksverify = false

@ -13,14 +13,14 @@ repos:
rev: v0.910-1
hooks:
- id: mypy
exclude: '^(pyextra)|(cereal)|(rednose)|(panda)|(laika)|(opendbc)|(laika_repo)|(rednose_repo)/'
exclude: '^(pyextra/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(opendbc/)|(laika_repo/)|(rednose_repo/)/'
additional_dependencies: ['git+https://github.com/numpy/numpy-stubs', 'types-requests', 'types-atomicwrites',
'types-pycurl']
- repo: https://github.com/PyCQA/flake8
rev: 4.0.1
hooks:
- id: flake8
exclude: '^(pyextra)|(cereal)|(rednose)|(panda)|(laika)|(opendbc)|(laika_repo)|(rednose_repo)|(selfdrive/debug)/'
exclude: '^(pyextra/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(opendbc/)|(laika_repo/)|(rednose_repo/)|(selfdrive/debug/)/'
args:
- --select=F,E112,E113,E304,E502,E701,E702,E703,E71,E72,E731,W191,W6
- --statistics
@ -31,7 +31,7 @@ repos:
entry: pylint
language: system
types: [python]
exclude: '^(pyextra)|(cereal)|(rednose)|(panda)|(laika)|(laika_repo)|(rednose_repo)/'
exclude: '^(pyextra/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(laika_repo/)|(rednose_repo/)/'
- repo: local
hooks:
- id: cppcheck
@ -39,7 +39,7 @@ repos:
entry: cppcheck
language: system
types: [c++]
exclude: '^(third_party)|(pyextra)|(cereal)|(opendbc)|(panda)|(tools)|(selfdrive/modeld/thneed/debug)|(selfdrive/modeld/test)|(selfdrive/camerad/test)/|(installer)'
exclude: '^(third_party/)|(pyextra/)|(cereal/)|(opendbc/)|(panda/)|(tools/)|(selfdrive/modeld/thneed/debug/)|(selfdrive/modeld/test/)|(selfdrive/camerad/test/)/|(installer/)'
args:
- --error-exitcode=1
- --language=c++

@ -1,70 +1,32 @@
FROM ubuntu:20.04
ENV PYTHONUNBUFFERED 1
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
autoconf \
build-essential \
bzip2 \
ca-certificates \
capnproto \
clang \
cmake \
cppcheck \
curl \
ffmpeg \
gcc-arm-none-eabi \
git \
iputils-ping \
libarchive-dev \
libbz2-dev \
libcapnp-dev \
libcurl4-openssl-dev \
libeigen3-dev \
libffi-dev \
libgles2-mesa-dev \
libglew-dev \
libglib2.0-0 \
liblzma-dev \
libomp-dev \
libopencv-dev \
libqt5sql5-sqlite \
libqt5svg5-dev \
libsqlite3-dev \
libssl-dev \
libsystemd-dev \
libusb-1.0-0-dev \
libzmq3-dev \
locales \
ocl-icd-libopencl1 \
ocl-icd-opencl-dev \
opencl-headers \
python-dev \
qml-module-qtquick2 \
qt5-default \
qtlocation5-dev \
qtmultimedia5-dev \
qtpositioning5-dev \
qtwebengine5-dev \
sudo \
valgrind \
wget \
&& rm -rf /var/lib/apt/lists/*
RUN apt-get update && \
apt-get install -y --no-install-recommends sudo tzdata locales && \
rm -rf /var/lib/apt/lists/*
RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8
RUN curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash
ENV PATH="/root/.pyenv/bin:/root/.pyenv/shims:${PATH}"
ENV PIPENV_SYSTEM=1
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 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 && \
COPY Pipfile Pipfile.lock /tmp/
RUN pyenv install 3.8.10 && \
pyenv global 3.8.10 && \
pyenv rehash && \
pip install --no-cache-dir --upgrade pip==21.3.1 && \
pip install --no-cache-dir pipenv==2021.5.29 && \
cd /tmp && \
pipenv install --system --deploy --dev --clear && \
pip uninstall -y pipenv
# remove unused architectures from gcc for panda
cd /usr/lib/gcc/arm-none-eabi/9.2.1 && \
rm -rf arm/ && \
rm -rf thumb/nofp thumb/v6* thumb/v8* thumb/v7+fp thumb/v7-r+fp.sp

@ -25,16 +25,20 @@ pre-commit = "*"
pycurl = "*"
pygame = "*"
pyprof2calltree = "*"
pytest = "*"
pytest-xdist = "*"
reverse_geocoder = "*"
scipy = "*"
sphinx = "*"
sphinx-sitemap = "*"
sphinx-rtd-theme = "*"
breathe = "*"
subprocess32 = "*"
tenacity = "*"
[packages]
atomicwrites = "*"
casadi = "*"
casadi = {version = "*", markers="platform_system != 'Darwin'"}
cffi = "*"
crcmod = "*"
cryptography = "*"
@ -50,7 +54,7 @@ libusb1 = "*"
nose = "*"
numpy = "*"
onnx = "*"
onnxruntime-gpu = "*"
onnxruntime-gpu = {version = "*", markers="platform_system != 'Darwin'"}
pillow = "*"
psutil = "*"
pycapnp = "==1.1.0"

1179
Pipfile.lock generated

File diff suppressed because it is too large Load Diff

@ -1,9 +1,28 @@
Version 0.8.12 (2021-12-XX)
Version 0.8.13 (2022-XX-XX)
========================
* Improved driver monitoring
* Improved camera focus on the comma two
* Subaru ECU firmware fingerprinting thanks to martinl!
* Hyundai Santa Fe Plug-in Hybrid 2022 support thanks to sunnyhaibin!
* Subaru Impreza 2020 support thanks to martinl!
Version 0.8.12 (2021-12-15)
========================
* New driving model
* Improved behavior around exits
* Better pose accuracy at high speeds, allowing max speed of 90mph
* Fully incorporated comma three data into all parts of training stack
* Improved follow distance
* Better longitudinal policy, especially in low speed traffic
* New alert sounds
* AGNOS 3
* Display burn in mitigation
* Improved audio amplifier configuration
* System reliability improvements
* Update Python to 3.8.10
* Raw logs upload moved to connect.comma.ai
* Fixed HUD alerts on newer Honda Bosch thanks to csouers!
* Audi Q3 2020-21 support thanks to jyoung8607!
* Honda Accord 2021 support thanks to csouers!
* Honda Accord Hybrid 2021 support thanks to csouers!
* Lexus RC 2020 support thanks to ErichMoraga!
Version 0.8.11 (2021-11-29)

@ -66,7 +66,7 @@ lenv = {
"LD_LIBRARY_PATH": [Dir(f"#third_party/acados/{arch}/lib").abspath],
"PYTHONPATH": Dir("#").abspath + ":" + Dir("#pyextra/").abspath,
"ACADOS_SOURCE_DIR": Dir("#third_party/acados/acados").abspath,
"ACADOS_SOURCE_DIR": Dir("#third_party/acados/include/acados").abspath,
"ACADOS_PYTHON_INTERFACE_PATH": Dir("#pyextra/acados_template").abspath,
"TERA_PATH": Dir("#").abspath + f"/third_party/acados/{arch}/t_renderer",
}
@ -125,14 +125,18 @@ else:
f"#third_party/libyuv/{yuv_dir}/lib",
"/usr/local/lib",
"/opt/homebrew/lib",
"/usr/local/Homebrew/Library",
"/usr/local/opt/openssl/lib",
"/opt/homebrew/opt/openssl/lib",
"/usr/local/Cellar",
f"#third_party/acados/{arch}/lib",
"/System/Library/Frameworks/OpenGL.framework/Libraries",
]
cflags += ["-DGL_SILENCE_DEPRECATION"]
cxxflags += ["-DGL_SILENCE_DEPRECATION"]
cpppath += [
"/opt/homebrew/include",
"/usr/local/include",
"/usr/local/opt/openssl/include",
"/opt/homebrew/opt/openssl/include"
]
@ -234,6 +238,9 @@ env = Environment(
tools=["default", "cython", "compilation_db"],
)
if arch == "Darwin":
env['RPATHPREFIX'] = "-rpath "
if GetOption('compile_db'):
env.CompilationDatabase('compile_commands.json')
@ -298,6 +305,7 @@ if arch == "Darwin":
qt_dirs += [f"{qt_env['QTDIR']}/include/Qt{m}" for m in qt_modules]
qt_env["LINKFLAGS"] += ["-F" + os.path.join(qt_env['QTDIR'], "lib")]
qt_env["FRAMEWORKS"] += [f"Qt{m}" for m in qt_modules] + ["OpenGL"]
qt_env.AppendENVPath('PATH', os.path.join(qt_env['QTDIR'], "bin"))
elif arch == "aarch64":
qt_env['QTDIR'] = "/system/comma/usr"
qt_dirs = [

@ -1 +1 @@
Subproject commit e5a04ab458afd52cf630cc9e35ccdc10efba6688
Subproject commit 42542ee96ca00744e6117d57533defe6f01ba14d

@ -28,7 +28,7 @@ def ffi_wrap(name, c_code, c_header, tmpdir="/tmp/ccache", cflags="", libraries=
try:
mod = __import__(cache)
except Exception:
print("cache miss {0}".format(cache))
print(f"cache miss {cache}")
compile_code(cache, c_code, c_header, tmpdir, cflags, libraries)
mod = __import__(cache)
finally:

@ -35,7 +35,7 @@ def get_tmpdir_on_same_filesystem(path):
if len(parts) > 1 and parts[1] == "scratch":
return "/scratch/tmp"
elif len(parts) > 2 and parts[2] == "runner":
return "/{}/runner/tmp".format(parts[1])
return f"/{parts[1]}/runner/tmp"
return "/tmp"
@ -81,6 +81,17 @@ def _get_fileobject_func(writer, temp_dir):
return writer.get_fileobject(dir=temp_dir)
return _get_fileobject
def monkeypatch_os_link():
# This is neccesary on EON/C2, where os.link is patched out of python
if not hasattr(os, 'link'):
from cffi import FFI
ffi = FFI()
ffi.cdef("int link(const char *oldpath, const char *newpath);")
libc = ffi.dlopen(None)
def link(src, dest):
return libc.link(src.encode(), dest.encode())
os.link = link
def atomic_write_on_fs_tmp(path, **kwargs):
"""Creates an atomic writer using a temporary file in a temporary directory
@ -88,6 +99,7 @@ def atomic_write_on_fs_tmp(path, **kwargs):
"""
# TODO(mgraczyk): This use of AtomicWriter relies on implementation details to set the temp
# directory.
monkeypatch_os_link()
writer = AtomicWriter(path, **kwargs)
return writer._open(_get_fileobject_func(writer, get_tmpdir_on_same_filesystem(path)))
@ -96,5 +108,6 @@ def atomic_write_in_dir(path, **kwargs):
"""Creates an atomic writer using a temporary file in the same directory
as the destination file.
"""
monkeypatch_os_link()
writer = AtomicWriter(path, **kwargs)
return writer._open(_get_fileobject_func(writer, os.path.dirname(path)))

@ -42,4 +42,4 @@ class Profiler():
print("%30s: %9.2f avg: %7.2f percent: %3.0f IGNORED" % (n, ms*1000.0, ms*1000.0/self.iter, ms/self.tot*100))
else:
print("%30s: %9.2f avg: %7.2f percent: %3.0f" % (n, ms*1000.0, ms*1000.0/self.iter, ms/self.tot*100))
print("Iter clock: %2.6f TOTAL: %2.2f" % (self.tot/self.iter, self.tot))
print(f"Iter clock: {self.tot / self.iter:2.6f} TOTAL: {self.tot:2.2f}")

@ -39,7 +39,7 @@ def set_realtime_priority(level: int) -> None:
def set_core_affinity(core: int) -> None:
if not PC:
os.sched_setaffinity(0, [core,])
os.sched_setaffinity(0, [core,]) # type: ignore[attr-defined]
def config_realtime_process(core: int, priority: int) -> None:
@ -79,7 +79,7 @@ class Ratekeeper:
remaining = self._next_frame_time - sec_since_boot()
self._next_frame_time += self._interval
if self._print_delay_threshold is not None and remaining < -self._print_delay_threshold:
print("%s lagging by %.2f ms" % (self._process_name, -remaining * 1000))
print(f"{self._process_name} lagging by {-remaining * 1000:.2f} ms")
lagged = True
self._frame += 1
self._remaining = remaining

@ -24,7 +24,7 @@ class Spinner():
except BrokenPipeError:
pass
def update_progress(self, cur: int, total: int):
def update_progress(self, cur: float, total: float):
self.update(str(round(100 * cur / total)))
def close(self):

@ -8,7 +8,7 @@ from common.file_helpers import atomic_write_in_dir
class TestFileHelpers(unittest.TestCase):
def run_atomic_write_func(self, atomic_write_func):
path = "/tmp/tmp{}".format(uuid4())
path = f"/tmp/tmp{uuid4()}"
with atomic_write_func(path) as f:
f.write("test")

@ -12,7 +12,7 @@ class Timeout:
"""
def __init__(self, seconds, error_msg=None):
if error_msg is None:
error_msg = 'Timed out after {} seconds'.format(seconds)
error_msg = f'Timed out after {seconds} seconds'
self.seconds = seconds
self.error_msg = error_msg

@ -125,7 +125,7 @@ def normalize(img_pts, intrinsics=fcam_intrinsics):
return img_pts_normalized[:, :2].reshape(input_shape)
def denormalize(img_pts, intrinsics=fcam_intrinsics, width=W, height=H):
def denormalize(img_pts, intrinsics=fcam_intrinsics, width=np.inf, height=np.inf):
# denormalizes image coordinates
# accepts single pt or array of pts
img_pts = np.array(img_pts)
@ -133,10 +133,12 @@ def denormalize(img_pts, intrinsics=fcam_intrinsics, width=W, height=H):
img_pts = np.atleast_2d(img_pts)
img_pts = np.hstack((img_pts, np.ones((img_pts.shape[0], 1), dtype=img_pts.dtype)))
img_pts_denormalized = img_pts.dot(intrinsics.T)
img_pts_denormalized[img_pts_denormalized[:, 0] > width] = np.nan
img_pts_denormalized[img_pts_denormalized[:, 0] < 0] = np.nan
img_pts_denormalized[img_pts_denormalized[:, 1] > height] = np.nan
img_pts_denormalized[img_pts_denormalized[:, 1] < 0] = np.nan
if np.isfinite(width):
img_pts_denormalized[img_pts_denormalized[:, 0] > width] = np.nan
img_pts_denormalized[img_pts_denormalized[:, 0] < 0] = np.nan
if np.isfinite(height):
img_pts_denormalized[img_pts_denormalized[:, 1] > height] = np.nan
img_pts_denormalized[img_pts_denormalized[:, 1] < 0] = np.nan
return img_pts_denormalized[:, :2].reshape(input_shape)

@ -84,6 +84,12 @@ bigmodel_frame_from_road_frame = np.dot(bigmodel_intrinsics,
bigmodel_frame_from_calib_frame = np.dot(bigmodel_intrinsics,
get_view_frame_from_calib_frame(0, 0, 0, 0))
sbigmodel_frame_from_road_frame = np.dot(sbigmodel_intrinsics,
get_view_frame_from_road_frame(0, 0, 0, model_height))
sbigmodel_frame_from_calib_frame = np.dot(sbigmodel_intrinsics,
get_view_frame_from_calib_frame(0, 0, 0, 0))
medmodel_frame_from_road_frame = np.dot(medmodel_intrinsics,
get_view_frame_from_road_frame(0, 0, 0, model_height))

@ -62,7 +62,7 @@
| Toyota | Highlander Hybrid 2020-22 | All | openpilot | 0mph | 0mph |
| Toyota | Mirai 2021 | All | openpilot | 0mph | 0mph |
| Toyota | Prius 2016-20 | TSS-P | Stock<sup>3</sup>| 0mph | 0mph |
| Toyota | Prius 2021 | All | openpilot | 0mph | 0mph |
| Toyota | Prius 2021-22 | All | openpilot | 0mph | 0mph |
| Toyota | Prius Prime 2017-20 | All | Stock<sup>3</sup>| 0mph | 0mph |
| Toyota | Prius Prime 2021-22 | All | openpilot | 0mph | 0mph |
| Toyota | Rav4 2016-18 | TSS-P | Stock<sup>3</sup>| 20mph<sup>1</sup> | 0mph |
@ -115,6 +115,7 @@
| Hyundai | Santa Fe 2019-20 | All | Stock | 0mph | 0mph |
| Hyundai | Santa Fe 2021-22 | All | Stock | 0mph | 0mph |
| Hyundai | Santa Fe Hybrid 2022 | All | Stock | 0mph | 0mph |
| Hyundai | Santa Fe Plug-in Hybrid 2022 | All | Stock | 0mph | 0mph |
| Hyundai | Sonata 2018-2019 | SCC + LKAS | Stock | 0mph | 0mph |
| Hyundai | Sonata Hybrid 2021-22 | All | Stock | 0mph | 0mph |
| Hyundai | Veloster 2019-20 | SCC + LKAS | Stock | 5mph | 0mph |
@ -123,7 +124,7 @@
| Kia | Ceed 2019 | SCC + LKAS | Stock | 0mph | 0mph |
| Kia | Forte 2018-21 | SCC + LKAS | Stock | 0mph | 0mph |
| Kia | K5 2021-22 | SCC + LFA | Stock | 0mph | 0mph |
| Kia | Niro EV 2019-21 | SCC + LKAS | Stock | 0mph | 0mph |
| Kia | Niro EV 2019-22 | All | Stock | 0mph | 0mph |
| Kia | Niro Hybrid 2021 | SCC + LKAS | Stock | 0mph | 0mph |
| Kia | Niro PHEV 2019 | SCC + LKAS | Stock | 10mph | 32mph |
| Kia | Optima 2017 | SCC + LKAS | Stock | 0mph | 32mph |
@ -147,10 +148,10 @@
| Škoda | Scala 2020 | Driver Assistance | Stock | 0mph | 0mph |
| Škoda | Superb 2015-18 | Driver Assistance | Stock | 0mph | 0mph |
| Subaru | Ascent 2019 | EyeSight | Stock | 0mph | 0mph |
| Subaru | Crosstrek 2018-19 | EyeSight | Stock | 0mph | 0mph |
| Subaru | Crosstrek 2018-20 | EyeSight | Stock | 0mph | 0mph |
| Subaru | Forester 2019-21 | EyeSight | Stock | 0mph | 0mph |
| Subaru | Impreza 2017-19 | EyeSight | Stock | 0mph | 0mph |
| Volkswagen| Arteon 2021<sup>4</sup> | Driver Assistance | Stock | 0mph | 0mph |
| Volkswagen| Arteon 2018, 2021<sup>4</sup> | Driver Assistance | Stock | 0mph | 0mph |
| Volkswagen| Atlas 2018-19 | Driver Assistance | Stock | 0mph | 0mph |
| Volkswagen| California 2021<sup>4</sup> | Driver Assistance | Stock | 0mph | 32mph |
| Volkswagen| e-Golf 2014, 2019-20 | Driver Assistance | Stock | 0mph | 0mph |

@ -1,46 +1,48 @@
# How to contribute
Our software is open source so you can solve your own problems without needing help from others. And if you solve a problem and are so kind, you can upstream it for the rest of the world to use.
Our software is open source so you can solve your own problems without needing help from others. And if you solve a problem and are so kind, you can upstream it for the rest of the world to use. Check out our [post about externalization](https://blog.comma.ai/a-2020-theme-externalization/).
Most open source development activity is coordinated through our [GitHub Discussions](https://github.com/commaai/openpilot/discussions) and [Discord](https://discord.comma.ai). A lot of documentation is available on our [blog](https://blog.comma.ai/).
Most open source development activity is coordinated through our [GitHub Discussions](https://github.com/commaai/openpilot/discussions) and [Discord](https://discord.comma.ai). A lot of documentation is available at https://docs.comma.ai and on our [blog](https://blog.comma.ai/).
## Getting Started
### Getting Started
* Setup your [development environment](../tools/)
* Join our [Discord](https://discord.comma.ai)
* Make sure you have a [GitHub account](https://github.com/signup/free)
* Fork [our repositories](https://github.com/commaai) on GitHub
## Testing
### First contribution
Try out some of these first pull requests ideas to dive into the codebase:
### Automated Testing
* Increase our [mypy](http://mypy-lang.org/) coverage
* Write some documentation
* Tackle an open [good first issue](https://github.com/commaai/openpilot/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)
All PRs and commits are automatically checked by GitHub Actions. Check out `.github/workflows/` for what GitHub Actions runs. Any new tests should be added to GitHub Actions.
## Pull Requests
### Code Style and Linting
Pull requests should be against the master branch. Welcomed contributions include bug reports, car ports, and any [open issue](https://github.com/commaai/openpilot/issues). If you're unsure about a contribution, feel free to open a discussion, issue, or draft PR to discuss the problem you're trying to solve.
Code is automatically checked for style by GitHub Actions as part of the automated tests. You can also run these tests yourself by running `pre-commit run --all`.
A good pull request has all of the following:
* a clearly stated purpose
* every line changed directly contributes to the stated purpose
* verification, i.e. how did you test your PR?
* justification
* if you've optimized something, post benchmarks to prove it's better
* if you've improved your car's tuning, post before and after plots
* passes the CI tests
## Car Ports
### Car Ports
We've released a [Model Port guide](https://blog.comma.ai/openpilot-port-guide-for-toyota-models/) for porting to Toyota/Lexus models.
If you port openpilot to a substantially new car brand, see this more generic [Brand Port guide](https://blog.comma.ai/how-to-write-a-car-port-for-openpilot/).
## Pull Requests
## Testing
Pull requests should be against the master branch. Before running master on in-car hardware, you'll need to clone the submodules too. That can be done by recursively cloning the repository:
```
git clone https://github.com/commaai/openpilot.git --recursive
```
Or alternatively, when on the master branch:
```
git submodule update --init
```
The reasons for having submodules on a dedicated repository and our new development philosophy can be found in our [post about externalization](https://blog.comma.ai/a-2020-theme-externalization/).
Modules that are in seperate repositories include:
* cereal
* laika
* opendbc
* panda
* rednose
### Automated Testing
All PRs and commits are automatically checked by GitHub Actions. Check out `.github/workflows/` for what GitHub Actions runs. Any new tests should be added to GitHub Actions.
### Code Style and Linting
Code is automatically checked for style by GitHub Actions as part of the automated tests. You can also run these tests yourself by running `pre-commit run --all`.

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

@ -0,0 +1,2 @@
User-agent: *
Sitemap: https://docs.comma.ai/sitemap.xml

@ -0,0 +1,105 @@
openpilot
==========
opendbc
------
.. autodoxygenindex::
:project: opendbc_can
cereal
------
messaging
^^^^^^^^^
.. autodoxygenindex::
:project: cereal_messaging
visionipc
^^^^^^^^^
.. autodoxygenindex::
:project: cereal_visionipc
selfdrive
---------
camerad
^^^^^^^
.. autodoxygenindex::
:project: selfdrive_camerad_cameras
.. autodoxygenindex::
:project: selfdrive_camerad_transforms
.. autodoxygenindex::
:project: selfdrive_camerad_imgproc
locationd
^^^^^^^^^
.. autodoxygenindex::
:project: selfdrive_locationd
ui
^^
.. autodoxygenindex::
:project: selfdrive_ui
soundd
""""""
.. autodoxygenindex::
:project: selfdrive_ui_soundd
navd
""""
.. autodoxygenindex::
:project: selfdrive_ui_navd
replay
""""""
.. autodoxygenindex::
:project: selfdrive_ui_replay
qt
""
.. autodoxygenindex::
:project: selfdrive_ui_qt_offroad
.. autodoxygenindex::
:project: selfdrive_ui_qt_maps
proclogd
^^^^^^^^
.. autodoxygenindex::
:project: selfdrive_proclogd
modeld
^^^^^^
.. autodoxygenindex::
:project: selfdrive_modeld_transforms
.. autodoxygenindex::
:project: selfdrive_modeld_models
.. autodoxygenindex::
:project: selfdrive_modeld_thneed
.. autodoxygenindex::
:project: selfdrive_modeld_runners
common
^^^^^^
.. autodoxygenindex::
:project: selfdrive_common
sensorsd
^^^^^^^^
.. autodoxygenindex::
:project: selfdrive_sensord_sensors
boardd
^^^^^^
.. autodoxygenindex::
:project: selfdrive_boardd
rednose
-------
.. autodoxygenindex::
:project: rednose_repo_rednose_helpers

@ -14,17 +14,24 @@
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os
from os.path import exists
import sys
from selfdrive.version import get_version
from common.basedir import BASEDIR
sys.path.insert(0, os.path.abspath('.'))
sys.path.insert(0, os.path.abspath('..'))
VERSION = get_version()
# -- Project information -----------------------------------------------------
project = 'openpilot'
project = 'openpilot docs'
copyright = '2021, comma.ai'
author = 'comma.ai'
version = VERSION
release = VERSION
language = 'en'
# -- General configuration ---------------------------------------------------
@ -33,12 +40,39 @@ author = 'comma.ai'
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc', # Auto-generate docs
'sphinx.ext.viewcode', # Add view code link to modules
'sphinx_rtd_theme', # Read The Docs theme
'myst_parser', # Markdown parsing
'sphinx.ext.autodoc', # Auto-generate docs
'sphinx.ext.viewcode', # Add view code link to modules
'sphinx_rtd_theme', # Read The Docs theme
'myst_parser', # Markdown parsing
'breathe', # Doxygen C/C++ integration
'sphinx_sitemap', # sitemap generation for SEO
]
myst_html_meta = {
"description": "openpilot docs",
"keywords": "op, openpilot, docs, documentation",
"robots": "all,follow",
"googlebot": "index,follow,snippet,archive",
"property=og:locale": "en_US",
"property=og:site_name": "docs.comma.ai",
"property=og:url": "https://docs.comma.ai",
"property=og:title": "openpilot Docuemntation",
"property=og:type": "website",
"property=og:image:type": "image/jpeg",
"property=og:image:width": "400",
"property=og:image": "https://docs.comma.ai/_static/logo.png",
"property=og:image:url": "https://docs.comma.ai/_static/logo.png",
"property=og:image:secure_url": "https://docs.comma.ai/_static/logo.png",
"property=og:description": "openpilot Documentation",
"property=twitter:card": "summary_large_image",
"property=twitter:logo": "https://docs.comma.ai/_static/logo.png",
"property=twitter:title": "openpilot Documentation",
"property=twitter:description": "openpilot Documentation"
}
html_baseurl = 'https://docs.comma.ai/'
sitemap_filename = "sitemap.xml"
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
@ -48,14 +82,65 @@ templates_path = ['_templates']
exclude_patterns = []
# -- c docs configuration ---------------------------------------------------
# Breathe Configuration
# breathe_default_project = "c_docs"
breathe_build_directory = f"{BASEDIR}/build/docs/html/xml"
breathe_separate_member_pages = True
breathe_default_members = ('members', 'private-members', 'undoc-members')
breathe_domain_by_extension = {
"h": "cc",
}
breathe_implementation_filename_extensions = ['.c', '.cc']
breathe_doxygen_config_options = {}
breathe_projects_source = {}
# only document files that have accompanying .cc files next to them
print("searching for c_docs...")
for root, dirs, files in os.walk(BASEDIR):
found = False
breath_src = {}
breathe_srcs_list = []
for file in files:
ccFile = os.path.join(root, file)[:-2] + ".cc"
if file.endswith(".h") and exists(ccFile):
f = os.path.join(root, file)
parent_dir_abs = os.path.dirname(f)
parent_dir = parent_dir_abs[len(BASEDIR) + 1:]
parent_project = parent_dir.replace('/', '_')
print(f"\tFOUND: {f} in {parent_project}")
breathe_srcs_list.append(file)
found = True
if found:
breath_src[parent_project] = (parent_dir_abs, breathe_srcs_list)
breathe_projects_source.update(breath_src)
print(f"breathe_projects_source: {breathe_projects_source.keys()}")
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'
html_show_copyright = True
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
html_logo = '_static/logo.png'
html_favicon = '_static/favicon.ico'
html_theme_options = {
'logo_only': False,
'display_version': True,
'vcs_pageview_mode': 'blob',
'style_nav_header_background': '#000000',
}
html_extra_path = ['_static']

@ -34,6 +34,7 @@ COPY ./*.md ${OPENPILOT_PATH}/
RUN scons -j$(nproc)
RUN apt update && apt install doxygen -y
COPY ./docs ${OPENPILOT_PATH}/docs
RUN git init .
WORKDIR ${OPENPILOT_PATH}/docs

@ -28,8 +28,15 @@ overview.rst
- {ref}`search`
```{toctree}
:caption: 'Modules'
:caption: 'Python API'
:maxdepth: 2
modules.rst
```
```{toctree}
:caption: 'C/C++ API'
:maxdepth: 4
c_docs.rst
```

@ -11,7 +11,7 @@ if [ -z "$REQUIRED_NEOS_VERSION" ]; then
fi
if [ -z "$AGNOS_VERSION" ]; then
export AGNOS_VERSION="2"
export AGNOS_VERSION="3"
fi
if [ -z "$PASSIVE" ]; then

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ebb75bbd4c19994752f038f181359dce358a2c95c4ad1760d2d1ee346a45503d
oid sha256:209e9544e456dbc2a7d60490da65154e129bc84830909d8d931f97b3df93949b
size 56684955

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6e004a9ff90304fd3dfd661f3f52886affa677d486ff78c131d8a4887757b5f1
size 57552499
oid sha256:2365bae967cce21ce68707c30bf2981bb7081ee5c3e6a3dff793e660f23ff622
size 57554657

@ -1 +1 @@
Subproject commit 6efaf246a90b513995a374a9939e4e051cf1b41c
Subproject commit e286083a49d9e386e778dcbcd41de4829a958735

@ -1 +1 @@
Subproject commit d1efddfaa9ebf0ef82db3ba2842f35ce22e06f7e
Subproject commit f5857bc8fd3e1d2c27df342df85e202c7e844911

@ -77,6 +77,7 @@ selfdrive/tombstoned.py
selfdrive/pandad.py
selfdrive/updated.py
selfdrive/rtshield.py
selfdrive/statsd.py
selfdrive/athena/__init__.py
selfdrive/athena/athenad.py
@ -596,7 +597,6 @@ opendbc/lexus_rx_350_2016_pt_generated.dbc
opendbc/lexus_rx_hybrid_2017_pt_generated.dbc
opendbc/toyota_nodsu_pt_generated.dbc
opendbc/toyota_nodsu_hybrid_pt_generated.dbc
opendbc/toyota_camry_hybrid_2018_pt_generated.dbc
opendbc/toyota_highlander_2017_pt_generated.dbc
opendbc/toyota_highlander_hybrid_2018_pt_generated.dbc
opendbc/toyota_avalon_2017_pt_generated.dbc

@ -11,6 +11,7 @@ import select
import socket
import threading
import time
import tempfile
from collections import namedtuple
from functools import partial
from typing import Any
@ -31,10 +32,11 @@ from selfdrive.loggerd.config import ROOT
from selfdrive.loggerd.xattr_cache import getxattr, setxattr
from selfdrive.swaglog import cloudlog, SWAGLOG_DIR
from selfdrive.version import get_version, get_origin, get_short_branch, get_commit
from selfdrive.statsd import STATS_DIR
ATHENA_HOST = os.getenv('ATHENA_HOST', 'wss://athena.comma.ai')
HANDLER_THREADS = int(os.getenv('HANDLER_THREADS', "4"))
LOCAL_PORT_WHITELIST = set([8022])
LOCAL_PORT_WHITELIST = {8022}
LOG_ATTR_NAME = 'user.upload'
LOG_ATTR_VALUE_MAX_UNIX_TIME = int.to_bytes(2147483647, 4, sys.byteorder)
@ -48,7 +50,7 @@ dispatcher["echo"] = lambda s: s
recv_queue: Any = queue.Queue()
send_queue: Any = queue.Queue()
upload_queue: Any = queue.Queue()
log_send_queue: Any = queue.Queue()
low_priority_send_queue: Any = queue.Queue()
log_recv_queue: Any = queue.Queue()
cancelled_uploads: Any = set()
UploadItem = namedtuple('UploadItem', ['path', 'url', 'headers', 'created_at', 'id', 'retry_count', 'current', 'progress'], defaults=(0, False, 0))
@ -56,6 +58,28 @@ UploadItem = namedtuple('UploadItem', ['path', 'url', 'headers', 'created_at', '
cur_upload_items = {}
class UploadQueueCache():
params = Params()
@staticmethod
def initialize(upload_queue):
try:
upload_queue_json = UploadQueueCache.params.get("AthenadUploadQueue")
if upload_queue_json is not None:
for item in json.loads(upload_queue_json):
upload_queue.put(UploadItem(**item))
except Exception:
cloudlog.exception("athena.UploadQueueCache.initialize.exception")
@staticmethod
def cache(upload_queue):
try:
items = [i._asdict() for i in upload_queue.queue if i.id not in cancelled_uploads]
UploadQueueCache.params.put("AthenadUploadQueue", json.dumps(items))
except Exception:
cloudlog.exception("athena.UploadQueueCache.cache.exception")
def handle_long_poll(ws):
end_event = threading.Event()
@ -64,6 +88,7 @@ def handle_long_poll(ws):
threading.Thread(target=ws_send, args=(ws, end_event), name='ws_send'),
threading.Thread(target=upload_handler, args=(end_event,), name='upload_handler'),
threading.Thread(target=log_handler, args=(end_event,), name='log_handler'),
threading.Thread(target=stat_handler, args=(end_event,), name='stat_handler'),
] + [
threading.Thread(target=jsonrpc_handler, args=(end_event,), name=f'worker_{x}')
for x in range(HANDLER_THREADS)
@ -111,6 +136,7 @@ def upload_handler(end_event):
try:
cur_upload_items[tid] = upload_queue.get(timeout=1)._replace(current=True)
if cur_upload_items[tid].id in cancelled_uploads:
cancelled_uploads.remove(cur_upload_items[tid].id)
continue
@ -120,6 +146,7 @@ def upload_handler(end_event):
cur_upload_items[tid] = cur_upload_items[tid]._replace(progress=cur / sz if sz else 1)
_do_upload(cur_upload_items[tid], cb)
UploadQueueCache.cache(upload_queue)
except (requests.exceptions.Timeout, requests.exceptions.ConnectionError, requests.exceptions.SSLError) as e:
cloudlog.warning(f"athena.upload_handler.retry {e} {cur_upload_items[tid]}")
@ -131,6 +158,8 @@ def upload_handler(end_event):
current=False
)
upload_queue.put_nowait(item)
UploadQueueCache.cache(upload_queue)
cur_upload_items[tid] = None
for _ in range(RETRY_DELAY):
@ -237,19 +266,35 @@ def reboot():
@dispatcher.add_method
def uploadFileToUrl(fn, url, headers):
if len(fn) == 0 or fn[0] == '/' or '..' in fn:
return 500
path = os.path.join(ROOT, fn)
if not os.path.exists(path):
return 404
return uploadFilesToUrls([[fn, url, headers]])
@dispatcher.add_method
def uploadFilesToUrls(files_data):
items = []
failed = []
for fn, url, headers in files_data:
if len(fn) == 0 or fn[0] == '/' or '..' in fn:
failed.append(fn)
continue
path = os.path.join(ROOT, fn)
if not os.path.exists(path):
failed.append(fn)
continue
item = UploadItem(path=path, url=url, headers=headers, created_at=int(time.time() * 1000), id=None)
upload_id = hashlib.sha1(str(item).encode()).hexdigest()
item = item._replace(id=upload_id)
item = UploadItem(path=path, url=url, headers=headers, created_at=int(time.time() * 1000), id=None)
upload_id = hashlib.sha1(str(item).encode()).hexdigest()
item = item._replace(id=upload_id)
upload_queue.put_nowait(item)
items.append(item._asdict())
upload_queue.put_nowait(item)
UploadQueueCache.cache(upload_queue)
return {"enqueued": 1, "item": item._asdict()}
resp = {"enqueued": len(items), "items": items}
if failed:
resp["failed"] = failed
return resp
@dispatcher.add_method
@ -260,11 +305,15 @@ def listUploadQueue():
@dispatcher.add_method
def cancelUpload(upload_id):
upload_ids = set(item.id for item in list(upload_queue.queue))
if upload_id not in upload_ids:
if not isinstance(upload_id, list):
upload_id = [upload_id]
uploading_ids = {item.id for item in list(upload_queue.queue)}
cancelled_ids = uploading_ids.intersection(upload_id)
if len(cancelled_ids) == 0:
return 404
cancelled_uploads.add(upload_id)
cancelled_uploads.update(cancelled_ids)
return {"success": 1}
@ -280,8 +329,7 @@ def startLocalProxy(global_end_event, remote_ws_uri, local_port):
cloudlog.debug("athena.startLocalProxy.starting")
params = Params()
dongle_id = params.get("DongleId").decode('utf8')
dongle_id = Params().get("DongleId").decode('utf8')
identity_token = Api(dongle_id).get_token()
ws = create_connection(remote_ws_uri,
cookie="jwt=" + identity_token,
@ -312,7 +360,7 @@ def getPublicKey():
if not os.path.isfile(PERSIST + '/comma/id_rsa.pub'):
return None
with open(PERSIST + '/comma/id_rsa.pub', 'r') as f:
with open(PERSIST + '/comma/id_rsa.pub') as f:
return f.read()
@ -393,7 +441,7 @@ def log_handler(end_event):
curr_time = int(time.time())
log_path = os.path.join(SWAGLOG_DIR, log_entry)
setxattr(log_path, LOG_ATTR_NAME, int.to_bytes(curr_time, 4, sys.byteorder))
with open(log_path, "r") as f:
with open(log_path) as f:
jsonrpc = {
"method": "forwardLogs",
"params": {
@ -402,7 +450,7 @@ def log_handler(end_event):
"jsonrpc": "2.0",
"id": log_entry
}
log_send_queue.put_nowait(json.dumps(jsonrpc))
low_priority_send_queue.put_nowait(json.dumps(jsonrpc))
curr_log = log_entry
except OSError:
pass # file could be deleted by log rotation
@ -433,6 +481,32 @@ def log_handler(end_event):
cloudlog.exception("athena.log_handler.exception")
def stat_handler(end_event):
while not end_event.is_set():
last_scan = 0
curr_scan = sec_since_boot()
try:
if curr_scan - last_scan > 10:
stat_filenames = list(filter(lambda name: not name.startswith(tempfile.gettempprefix()), os.listdir(STATS_DIR)))
if len(stat_filenames) > 0:
stat_path = os.path.join(STATS_DIR, stat_filenames[0])
with open(stat_path) as f:
jsonrpc = {
"method": "storeStats",
"params": {
"stats": f.read()
},
"jsonrpc": "2.0",
"id": stat_filenames[0]
}
low_priority_send_queue.put_nowait(json.dumps(jsonrpc))
os.remove(stat_path)
last_scan = curr_scan
except Exception:
cloudlog.exception("athena.stat_handler.exception")
time.sleep(0.1)
def ws_proxy_recv(ws, local_sock, ssock, end_event, global_end_event):
while not (end_event.is_set() or global_end_event.is_set()):
try:
@ -505,7 +579,7 @@ def ws_send(ws, end_event):
try:
data = send_queue.get_nowait()
except queue.Empty:
data = log_send_queue.get(timeout=1)
data = low_priority_send_queue.get(timeout=1)
for i in range(0, len(data), WS_FRAME_SIZE):
frame = data[i:i+WS_FRAME_SIZE]
last = i + WS_FRAME_SIZE >= len(data)
@ -525,6 +599,7 @@ def backoff(retries):
def main():
params = Params()
dongle_id = params.get("DongleId", encoding='utf-8')
UploadQueueCache.initialize(upload_queue)
ws_uri = ATHENA_HOST + "/ws/v2/" + dongle_id
api = Api(dongle_id)

@ -6,7 +6,7 @@ from multiprocessing import Process
from common.params import Params
from selfdrive.manager.process import launcher
from selfdrive.swaglog import cloudlog
from selfdrive.version import get_version, get_dirty
from selfdrive.version import get_version, is_dirty
ATHENA_MGR_PID_PARAM = "AthenadPid"
@ -14,12 +14,12 @@ ATHENA_MGR_PID_PARAM = "AthenadPid"
def main():
params = Params()
dongle_id = params.get("DongleId").decode('utf-8')
cloudlog.bind_global(dongle_id=dongle_id, version=get_version(), dirty=get_dirty())
cloudlog.bind_global(dongle_id=dongle_id, version=get_version(), dirty=is_dirty())
try:
while 1:
cloudlog.info("starting athena daemon")
proc = Process(name='athenad', target=launcher, args=('selfdrive.athena.athenad',))
proc = Process(name='athenad', target=launcher, args=('selfdrive.athena.athenad', 'athenad'))
proc.start()
proc.join()
cloudlog.event("athenad exited", exitcode=proc.exitcode)

@ -1,4 +1,4 @@
#/!/usr/bin/env python3
#!/usr/bin/env python3
import time
import json
import jwt

@ -50,18 +50,28 @@ class MockApi():
class MockParams():
def __init__(self):
self.params = {
"DongleId": b"0000000000000000",
"GithubSshKeys": b"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC307aE+nuHzTAgaJhzSf5v7ZZQW9gaperjhCmyPyl4PzY7T1mDGenTlVTN7yoVFZ9UfO9oMQqo0n1OwDIiqbIFxqnhrHU0cYfj88rI85m5BEKlNu5RdaVTj1tcbaPpQc5kZEolaI1nDDjzV0lwS7jo5VYDHseiJHlik3HH1SgtdtsuamGR2T80q1SyW+5rHoMOJG73IH2553NnWuikKiuikGHUYBd00K1ilVAK2xSiMWJp55tQfZ0ecr9QjEsJ+J/efL4HqGNXhffxvypCXvbUYAFSddOwXUPo5BTKevpxMtH+2YrkpSjocWA04VnTYFiPG6U4ItKmbLOTFZtPzoez private" # noqa: E501
}
default_params = {
"DongleId": b"0000000000000000",
"GithubSshKeys": b"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC307aE+nuHzTAgaJhzSf5v7ZZQW9gaperjhCmyPyl4PzY7T1mDGenTlVTN7yoVFZ9UfO9oMQqo0n1OwDIiqbIFxqnhrHU0cYfj88rI85m5BEKlNu5RdaVTj1tcbaPpQc5kZEolaI1nDDjzV0lwS7jo5VYDHseiJHlik3HH1SgtdtsuamGR2T80q1SyW+5rHoMOJG73IH2553NnWuikKiuikGHUYBd00K1ilVAK2xSiMWJp55tQfZ0ecr9QjEsJ+J/efL4HqGNXhffxvypCXvbUYAFSddOwXUPo5BTKevpxMtH+2YrkpSjocWA04VnTYFiPG6U4ItKmbLOTFZtPzoez private", # noqa: E501
"AthenadUploadQueue": '[]'
}
params = default_params.copy()
@staticmethod
def restore_defaults():
MockParams.params = MockParams.default_params.copy()
def get(self, k, encoding=None):
ret = self.params.get(k)
ret = MockParams.params.get(k)
if ret is not None and encoding is not None:
ret = ret.decode(encoding)
return ret
def put(self, k, v):
if k not in MockParams.params:
raise KeyError(f"key: {k} not in MockParams")
MockParams.params[k] = v
class MockWebsocket():
def __init__(self, recv_queue, send_queue):

@ -21,19 +21,22 @@ from selfdrive.athena.athenad import MAX_RETRY_COUNT, dispatcher
from selfdrive.athena.tests.helpers import MockWebsocket, MockParams, MockApi, EchoSocket, with_http_server
from cereal import messaging
class TestAthenadMethods(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.SOCKET_PORT = 45454
athenad.Params = MockParams
athenad.ROOT = tempfile.mkdtemp()
athenad.SWAGLOG_DIR = swaglog.SWAGLOG_DIR = tempfile.mkdtemp()
athenad.Params = MockParams
athenad.Api = MockApi
athenad.LOCAL_PORT_WHITELIST = set([cls.SOCKET_PORT])
athenad.LOCAL_PORT_WHITELIST = {cls.SOCKET_PORT}
def setUp(self):
MockParams.restore_defaults()
athenad.upload_queue = queue.Queue()
athenad.cur_upload_items.clear()
athenad.cancelled_uploads.clear()
for i in os.listdir(athenad.ROOT):
p = os.path.join(athenad.ROOT, i)
@ -131,15 +134,16 @@ class TestAthenadMethods(unittest.TestCase):
@with_http_server
def test_uploadFileToUrl(self, host):
not_exists_resp = dispatcher["uploadFileToUrl"]("does_not_exist.bz2", "http://localhost:1238", {})
self.assertEqual(not_exists_resp, 404)
self.assertEqual(not_exists_resp, {'enqueued': 0, 'items': [], 'failed': ['does_not_exist.bz2']})
fn = os.path.join(athenad.ROOT, 'qlog.bz2')
Path(fn).touch()
resp = dispatcher["uploadFileToUrl"]("qlog.bz2", f"{host}/qlog.bz2", {})
self.assertEqual(resp['enqueued'], 1)
self.assertDictContainsSubset({"path": fn, "url": f"{host}/qlog.bz2", "headers": {}}, resp['item'])
self.assertIsNotNone(resp['item'].get('id'))
self.assertNotIn('failed', resp)
self.assertDictContainsSubset({"path": fn, "url": f"{host}/qlog.bz2", "headers": {}}, resp['items'][0])
self.assertIsNotNone(resp['items'][0].get('id'))
self.assertEqual(athenad.upload_queue.qsize(), 1)
@with_http_server
@ -249,6 +253,26 @@ class TestAthenadMethods(unittest.TestCase):
items = dispatcher["listUploadQueue"]()
self.assertEqual(len(items), 0)
def test_upload_queue_persistence(self):
item1 = athenad.UploadItem(path="_", url="_", headers={}, created_at=int(time.time()), id='id1')
item2 = athenad.UploadItem(path="_", url="_", headers={}, created_at=int(time.time()), id='id2')
athenad.upload_queue.put_nowait(item1)
athenad.upload_queue.put_nowait(item2)
# Ensure cancelled items are not persisted
athenad.cancelled_uploads.add(item2.id)
# serialize item
athenad.UploadQueueCache.cache(athenad.upload_queue)
# deserialize item
athenad.upload_queue.queue.clear()
athenad.UploadQueueCache.initialize(athenad.upload_queue)
self.assertEqual(athenad.upload_queue.qsize(), 1)
self.assertDictEqual(athenad.upload_queue.queue[-1]._asdict(), item1._asdict())
@mock.patch('selfdrive.athena.athenad.create_connection')
def test_startLocalProxy(self, mock_create_connection):
end_event = threading.Event()

@ -205,17 +205,17 @@ Panda *usb_connect(std::string serial="", uint32_t index=0) {
}
void can_send_thread(std::vector<Panda *> pandas, bool fake_send) {
set_thread_name("boardd_can_send");
util::set_thread_name("boardd_can_send");
AlignedBuffer aligned_buf;
Context * context = Context::create();
SubSocket * subscriber = SubSocket::create(context, "sendcan");
std::unique_ptr<Context> context(Context::create());
std::unique_ptr<SubSocket> subscriber(SubSocket::create(context.get(), "sendcan"));
assert(subscriber != NULL);
subscriber->setTimeout(100);
// run as fast as messages come in
while (!do_exit && check_all_connected(pandas)) {
Message * msg = subscriber->receive();
std::unique_ptr<Message> msg(subscriber->receive());
if (!msg) {
if (errno == EINTR) {
do_exit = true;
@ -223,27 +223,20 @@ void can_send_thread(std::vector<Panda *> pandas, bool fake_send) {
continue;
}
capnp::FlatArrayMessageReader cmsg(aligned_buf.align(msg));
capnp::FlatArrayMessageReader cmsg(aligned_buf.align(msg.get()));
cereal::Event::Reader event = cmsg.getRoot<cereal::Event>();
//Dont send if older than 1 second
if (nanos_since_boot() - event.getLogMonoTime() < 1e9) {
if (!fake_send) {
for (const auto& panda : pandas) {
panda->can_send(event.getSendcan());
}
if ((nanos_since_boot() - event.getLogMonoTime() < 1e9) && !fake_send) {
for (const auto& panda : pandas) {
panda->can_send(event.getSendcan());
}
}
delete msg;
}
delete subscriber;
delete context;
}
void can_recv_thread(std::vector<Panda *> pandas) {
set_thread_name("boardd_can_recv");
util::set_thread_name("boardd_can_recv");
// can = 8006
PubMaster pm({"can"});
@ -415,9 +408,11 @@ void send_peripheral_state(PubMaster *pm, Panda *panda) {
}
void panda_state_thread(PubMaster *pm, std::vector<Panda *> pandas, bool spoofing_started) {
set_thread_name("boardd_panda_state");
util::set_thread_name("boardd_panda_state");
Params params;
SubMaster sm({"controlsState"});
Panda *peripheral_panda = pandas[0];
bool ignition_last = false;
std::future<bool> safety_future;
@ -452,8 +447,11 @@ void panda_state_thread(PubMaster *pm, std::vector<Panda *> pandas, bool spoofin
ignition_last = ignition;
sm.update(0);
const bool engaged = sm.allAliveAndValid({"controlsState"}) && sm["controlsState"].getControlsState().getEnabled();
for (const auto &panda : pandas) {
panda->send_heartbeat();
panda->send_heartbeat(engaged);
}
util::sleep_for(500);
}
@ -461,7 +459,7 @@ void panda_state_thread(PubMaster *pm, std::vector<Panda *> pandas, bool spoofin
void peripheral_control_thread(Panda *panda) {
set_thread_name("boardd_peripheral_control");
util::set_thread_name("boardd_peripheral_control");
SubMaster sm({"deviceState", "driverCameraState"});
@ -547,12 +545,12 @@ static void pigeon_publish_raw(PubMaster &pm, const std::string &dat) {
}
void pigeon_thread(Panda *panda) {
set_thread_name("boardd_pigeon");
util::set_thread_name("boardd_pigeon");
PubMaster pm({"ubloxRaw"});
bool ignition_last = false;
Pigeon *pigeon = Hardware::TICI() ? Pigeon::connect("/dev/ttyHS0") : Pigeon::connect(panda);
std::unique_ptr<Pigeon> pigeon(Hardware::TICI() ? Pigeon::connect("/dev/ttyHS0") : Pigeon::connect(panda));
std::unordered_map<char, uint64_t> last_recv_time;
std::unordered_map<char, int64_t> cls_max_dt = {
@ -620,8 +618,6 @@ void pigeon_thread(Panda *panda) {
// 10ms - 100 Hz
util::sleep_for(10);
}
delete pigeon;
}
int main(int argc, char *argv[]) {
@ -629,9 +625,9 @@ int main(int argc, char *argv[]) {
if (!Hardware::PC()) {
int err;
err = set_realtime_priority(54);
err = util::set_realtime_priority(54);
assert(err == 0);
err = set_core_affinity({Hardware::TICI() ? 4 : 3});
err = util::set_core_affinity({Hardware::TICI() ? 4 : 3});
assert(err == 0);
}
@ -662,6 +658,8 @@ int main(int argc, char *argv[]) {
Panda *peripheral_panda = pandas[0];
std::vector<std::thread> threads;
Params().put("LastPeripheralPandaType", std::to_string((int) peripheral_panda->get_hw_type()));
threads.emplace_back(panda_state_thread, &pm, pandas, getenv("STARTED") != nullptr);
threads.emplace_back(peripheral_control_thread, peripheral_panda);
threads.emplace_back(pigeon_thread, peripheral_panda);

@ -340,8 +340,8 @@ void Panda::set_usb_power_mode(cereal::PeripheralState::UsbPowerMode power_mode)
usb_write(0xe6, (uint16_t)power_mode, 0);
}
void Panda::send_heartbeat() {
usb_write(0xf3, 1, 0);
void Panda::send_heartbeat(bool engaged) {
usb_write(0xf3, engaged, 0);
}
void Panda::set_can_speed_kbps(uint16_t bus, uint16_t speed) {

@ -108,7 +108,7 @@ class Panda {
std::optional<std::string> get_serial();
void set_power_saving(bool power_saving);
void set_usb_power_mode(cereal::PeripheralState::UsbPowerMode power_mode);
void send_heartbeat();
void send_heartbeat(bool engaged);
void set_can_speed_kbps(uint16_t bus, uint16_t speed);
void set_data_speed_kbps(uint16_t bus, uint16_t speed);
void can_send(capnp::List<cereal::CanData>::Reader can_data_list);

@ -69,7 +69,7 @@ class TestBoardd(unittest.TestCase):
for __ in range(random.randrange(100)):
bus = random.choice([b for b in range(3*num_pandas) if b % 4 != 3])
addr = random.randrange(1, 1<<29)
dat = bytes([random.getrandbits(8) for _ in range(random.randrange(1, 9))])
dat = bytes(random.getrandbits(8) for _ in range(random.randrange(1, 9)))
sent_msgs[bus].add((addr, dat))
to_send.append(make_can_msg(addr, dat, bus))
sendcan.send(can_list_to_can_capnp(to_send, msgtype='sendcan'))

@ -200,7 +200,6 @@ void fill_frame_data(cereal::FrameData::Builder &framed, const FrameMetadata &fr
framed.setMeasuredGreyFraction(frame_data.measured_grey_fraction);
framed.setTargetGreyFraction(frame_data.target_grey_fraction);
framed.setLensPos(frame_data.lens_pos);
framed.setLensSag(frame_data.lens_sag);
framed.setLensErr(frame_data.lens_err);
framed.setLensTruePos(frame_data.lens_true_pos);
}
@ -351,7 +350,7 @@ void *processing_thread(MultiCameraState *cameras, CameraState *cs, process_thre
} else {
thread_name = "WideRoadCamera";
}
set_thread_name(thread_name);
util::set_thread_name(thread_name);
uint32_t cnt = 0;
while (!do_exit) {
@ -408,11 +407,11 @@ static void driver_cam_auto_exposure(CameraState *c, SubMaster &sm) {
camera_autoexposure(c, set_exposure_target(b, rect.x1, rect.x2, rect.x_skip, rect.y1, rect.y2, rect.y_skip));
}
void common_process_driver_camera(SubMaster *sm, PubMaster *pm, CameraState *c, int cnt) {
void common_process_driver_camera(MultiCameraState *s, CameraState *c, int cnt) {
int j = Hardware::TICI() ? 1 : 3;
if (cnt % j == 0) {
sm->update(0);
driver_cam_auto_exposure(c, *sm);
s->sm->update(0);
driver_cam_auto_exposure(c, *(s->sm));
}
MessageBuilder msg;
auto framed = msg.initEvent().initDriverCameraState();
@ -421,5 +420,5 @@ void common_process_driver_camera(SubMaster *sm, PubMaster *pm, CameraState *c,
if (env_send_driver) {
framed.setImage(get_frame_image(&c->buf));
}
pm->send("driverCameraState", msg);
s->pm->send("driverCameraState", msg);
}

@ -68,7 +68,6 @@ typedef struct FrameMetadata {
// Focus
unsigned int lens_pos;
float lens_sag;
float lens_err;
float lens_true_pos;
} FrameMetadata;
@ -123,7 +122,7 @@ void fill_frame_data(cereal::FrameData::Builder &framed, const FrameMetadata &fr
kj::Array<uint8_t> get_frame_image(const CameraBuf *b);
float set_exposure_target(const CameraBuf *b, int x_start, int x_end, int x_skip, int y_start, int y_end, int y_skip);
std::thread start_process_thread(MultiCameraState *cameras, CameraState *cs, process_thread_cb callback);
void common_process_driver_camera(SubMaster *sm, PubMaster *pm, CameraState *c, int cnt);
void common_process_driver_camera(MultiCameraState *s, CameraState *c, int cnt);
void cameras_init(VisionIpcServer *v, MultiCameraState *s, cl_device_id device_id, cl_context ctx);
void cameras_open(MultiCameraState *s);

@ -227,7 +227,7 @@ void cameras_init(VisionIpcServer *v, MultiCameraState *s, cl_device_id device_i
s->stats_bufs[i].allocate(0xb80);
}
std::fill_n(s->lapres, std::size(s->lapres), 16160);
s->lap_conv = new LapConv(device_id, ctx, s->road_cam.buf.rgb_width, s->road_cam.buf.rgb_height, 3);
s->lap_conv = new LapConv(device_id, ctx, s->road_cam.buf.rgb_width, s->road_cam.buf.rgb_height, s->road_cam.buf.rgb_stride, 3);
}
static void set_exposure(CameraState *s, float exposure_frac, float gain_frac) {
@ -852,21 +852,7 @@ static void parse_autofocus(CameraState *s, uint8_t *d) {
s->focus_err = max_focus*1.0;
}
static std::optional<float> get_accel_z(SubMaster *sm) {
sm->update(0);
if(sm->updated("sensorEvents")) {
for (auto event : (*sm)["sensorEvents"].getSensorEvents()) {
if (event.which() == cereal::SensorEventData::ACCELERATION) {
if (auto v = event.getAcceleration().getV(); v.size() >= 3)
return -v[2];
break;
}
}
}
return std::nullopt;
}
static void do_autofocus(CameraState *s, SubMaster *sm) {
static void do_autofocus(CameraState *s) {
float lens_true_pos = s->lens_true_pos.load();
if (!isnan(s->focus_err)) {
// learn lens_true_pos
@ -874,23 +860,10 @@ static void do_autofocus(CameraState *s, SubMaster *sm) {
lens_true_pos -= s->focus_err*focus_kp;
}
if (auto accel_z = get_accel_z(sm)) {
s->last_sag_acc_z = *accel_z;
}
const float sag = (s->last_sag_acc_z / 9.8) * 128;
// stay off the walls
lens_true_pos = std::clamp(lens_true_pos, float(LP3_AF_DAC_DOWN), float(LP3_AF_DAC_UP));
int target = std::clamp(lens_true_pos - sag, float(LP3_AF_DAC_DOWN), float(LP3_AF_DAC_UP));
s->lens_true_pos.store(lens_true_pos);
/*char debug[4096];
char *pdebug = debug;
pdebug += sprintf(pdebug, "focus ");
for (int i = 0; i < NUM_FOCUS; i++) pdebug += sprintf(pdebug, "%2x(%4d) ", s->confidence[i], s->focus[i]);
pdebug += sprintf(pdebug, " err: %7.2f offset: %6.2f sag: %6.2f lens_true_pos: %6.2f cur_lens_pos: %4d->%4d", err * focus_kp, offset, sag, s->lens_true_pos, s->cur_lens_pos, target);
LOGD(debug);*/
actuator_move(s, target);
actuator_move(s, lens_true_pos);
}
void camera_autoexposure(CameraState *s, float grey_frac) {
@ -1045,13 +1018,12 @@ static void ops_thread(MultiCameraState *s) {
CameraExpInfo road_cam_op;
CameraExpInfo driver_cam_op;
set_thread_name("camera_settings");
SubMaster sm({"sensorEvents"});
util::set_thread_name("camera_settings");
while(!do_exit) {
road_cam_op = road_cam_exp.load();
if (road_cam_op.op_id != last_road_cam_op_id) {
do_autoexposure(&s->road_cam, road_cam_op.grey_frac);
do_autofocus(&s->road_cam, &sm);
do_autofocus(&s->road_cam);
last_road_cam_op_id = road_cam_op.op_id;
}
@ -1086,10 +1058,6 @@ static void setup_self_recover(CameraState *c, const uint16_t *lapres, size_t la
c->self_recover.store(self_recover);
}
void process_driver_camera(MultiCameraState *s, CameraState *c, int cnt) {
common_process_driver_camera(s->sm, s->pm, c, cnt);
}
// called by processing_thread
void process_road_camera(MultiCameraState *s, CameraState *c, int cnt) {
const CameraBuf *b = &c->buf;
@ -1121,7 +1089,7 @@ void cameras_run(MultiCameraState *s) {
std::vector<std::thread> threads;
threads.push_back(std::thread(ops_thread, s));
threads.push_back(start_process_thread(s, &s->road_cam, process_road_camera));
threads.push_back(start_process_thread(s, &s->driver_cam, process_driver_camera));
threads.push_back(start_process_thread(s, &s->driver_cam, common_process_driver_camera));
CameraState* cameras[2] = {&s->road_cam, &s->driver_cam};
@ -1169,7 +1137,6 @@ void cameras_run(MultiCameraState *s) {
.frame_length = (uint32_t)c->frame_length,
.integ_lines = (uint32_t)c->cur_integ_lines,
.lens_pos = c->cur_lens_pos,
.lens_sag = c->last_sag_acc_z,
.lens_err = c->focus_err,
.lens_true_pos = c->lens_true_pos,
.gain = c->cur_gain_frac,

@ -76,7 +76,6 @@ typedef struct CameraState {
// rear camera only,used for focusing
unique_fd actuator_fd;
std::atomic<float> focus_err;
std::atomic<float> last_sag_acc_z;
std::atomic<float> lens_true_pos;
std::atomic<int> self_recover; // af recovery counter, neg is patience, pos is active
uint16_t cur_step_pos;

@ -987,11 +987,6 @@ void camera_autoexposure(CameraState *s, float grey_frac) {
set_camera_exposure(s, grey_frac);
}
void process_driver_camera(MultiCameraState *s, CameraState *c, int cnt) {
common_process_driver_camera(s->sm, s->pm, c, cnt);
}
// called by processing_thread
void process_road_camera(MultiCameraState *s, CameraState *c, int cnt) {
const CameraBuf *b = &c->buf;
@ -1016,7 +1011,7 @@ void cameras_run(MultiCameraState *s) {
LOG("-- Starting threads");
std::vector<std::thread> threads;
threads.push_back(start_process_thread(s, &s->road_cam, process_road_camera));
threads.push_back(start_process_thread(s, &s->driver_cam, process_driver_camera));
threads.push_back(start_process_thread(s, &s->driver_cam, common_process_driver_camera));
threads.push_back(start_process_thread(s, &s->wide_road_cam, process_road_camera));
// start devices

@ -67,12 +67,12 @@ void run_camera(CameraState *s) {
}
void road_camera_thread(CameraState *s) {
set_thread_name("replay_road_camera_thread");
util::set_thread_name("replay_road_camera_thread");
run_camera(s);
}
// void driver_camera_thread(CameraState *s) {
// set_thread_name("replay_driver_camera_thread");
// util::set_thread_name("replay_driver_camera_thread");
// run_camera(s);
// }

@ -97,7 +97,7 @@ void run_camera(CameraState *s, cv::VideoCapture &video_cap, float *ts) {
}
static void road_camera_thread(CameraState *s) {
set_thread_name("webcam_road_camera_thread");
util::set_thread_name("webcam_road_camera_thread");
cv::VideoCapture cap_road(ROAD_CAMERA_ID, cv::CAP_V4L2); // road
cap_road.set(cv::CAP_PROP_FRAME_WIDTH, 853);
@ -186,7 +186,7 @@ void cameras_run(MultiCameraState *s) {
threads.push_back(start_process_thread(s, &s->driver_cam, process_driver_camera));
std::thread t_rear = std::thread(road_camera_thread, &s->road_cam);
set_thread_name("webcam_thread");
util::set_thread_name("webcam_thread");
driver_camera_thread(&s->driver_cam);
t_rear.join();

@ -55,8 +55,8 @@ static cl_program build_conv_program(cl_device_id device_id, cl_context context,
return cl_program_from_file(context, device_id, "imgproc/conv.cl", args);
}
LapConv::LapConv(cl_device_id device_id, cl_context ctx, int rgb_width, int rgb_height, int filter_size)
: width(rgb_width / NUM_SEGMENTS_X), height(rgb_height / NUM_SEGMENTS_Y),
LapConv::LapConv(cl_device_id device_id, cl_context ctx, int rgb_width, int rgb_height, int rgb_stride, int filter_size)
: width(rgb_width / NUM_SEGMENTS_X), height(rgb_height / NUM_SEGMENTS_Y), rgb_stride(rgb_stride),
roi_buf(width * height * 3), result_buf(width * height) {
prg = build_conv_program(device_id, ctx, width, height, filter_size);
@ -81,9 +81,9 @@ uint16_t LapConv::Update(cl_command_queue q, const uint8_t *rgb_buf, const int r
const int x_offset = ROI_X_MIN + roi_id % (ROI_X_MAX - ROI_X_MIN + 1);
const int y_offset = ROI_Y_MIN + roi_id / (ROI_X_MAX - ROI_X_MIN + 1);
const uint8_t *rgb_offset = rgb_buf + y_offset * height * FULL_STRIDE_X * 3 + x_offset * width * 3;
const uint8_t *rgb_offset = rgb_buf + y_offset * height * rgb_stride + x_offset * width * 3;
for (int i = 0; i < height; ++i) {
memcpy(&roi_buf[i * width * 3], &rgb_offset[i * FULL_STRIDE_X * 3], width * 3);
memcpy(&roi_buf[i * width * 3], &rgb_offset[i * rgb_stride], width * 3);
}
constexpr int local_mem_size = (CONV_LOCAL_WORKSIZE + 2 * (3 / 2)) * (CONV_LOCAL_WORKSIZE + 2 * (3 / 2)) * (3 * sizeof(uint8_t));

@ -16,16 +16,11 @@
#define LM_THRESH 120
#define LM_PREC_THRESH 0.9 // 90 perc is blur
// only apply to QCOM
#define FULL_STRIDE_X 1280
#define FULL_STRIDE_Y 896
#define CONV_LOCAL_WORKSIZE 16
class LapConv {
public:
LapConv(cl_device_id device_id, cl_context ctx, int rgb_width, int rgb_height, int filter_size);
LapConv(cl_device_id device_id, cl_context ctx, int rgb_width, int rgb_height, int rgb_stride, int filter_size);
~LapConv();
uint16_t Update(cl_command_queue q, const uint8_t *rgb_buf, const int roi_id);
@ -34,6 +29,7 @@ private:
cl_program prg;
cl_kernel krnl;
const int width, height;
const int rgb_stride;
std::vector<uint8_t> roi_buf;
std::vector<int16_t> result_buf;
};

@ -46,9 +46,9 @@ void party(cl_device_id device_id, cl_context context) {
int main(int argc, char *argv[]) {
if (!Hardware::PC()) {
int ret;
ret = set_realtime_priority(53);
ret = util::set_realtime_priority(53);
assert(ret == 0);
ret = set_core_affinity({Hardware::EON() ? 2 : 6});
ret = util::set_core_affinity({Hardware::EON() ? 2 : 6});
assert(ret == 0 || Params().getBool("IsOffroad")); // failure ok while offroad due to offlining cores
}

@ -54,7 +54,7 @@ class TestCamerad(unittest.TestCase):
self.assertTrue(abs(dfid - 1) <= SKIP_FRAME_TOLERANCE, "%s frame id diff is %d" % (camera, dfid))
dts = ct - last_ts[camera]
self.assertTrue(abs(dts - (1000/CAMERAS[camera])) < LAG_FRAME_TOLERANCE, "%s frame t(ms) diff is %f" % (camera, dts))
self.assertTrue(abs(dts - (1000/CAMERAS[camera])) < LAG_FRAME_TOLERANCE, f"{camera} frame t(ms) diff is {dts:f}")
last_frame_id[camera] = sm[camera].frameId
last_ts[camera] = ct

@ -1,7 +1,7 @@
import os
from common.params import Params
from common.basedir import BASEDIR
from selfdrive.version import get_comma_remote, get_tested_branch
from selfdrive.version import is_comma_remote, is_tested_branch
from selfdrive.car.fingerprints import eliminate_incompatible_cars, all_legacy_fingerprint_cars
from selfdrive.car.vin import get_vin, VIN_UNKNOWN
from selfdrive.car.fw_versions import get_fw_versions, match_fw_to_car
@ -14,7 +14,7 @@ EventName = car.CarEvent.EventName
def get_startup_event(car_recognized, controller_available, fw_seen):
if get_comma_remote() and get_tested_branch():
if is_comma_remote() and is_tested_branch():
event = EventName.startup
else:
event = EventName.startupMaster
@ -39,7 +39,7 @@ def get_one_can(logcan):
def load_interfaces(brand_names):
ret = {}
for brand_name in brand_names:
path = ('selfdrive.car.%s' % brand_name)
path = f'selfdrive.car.{brand_name}'
CarInterface = __import__(path + '.interface', fromlist=['CarInterface']).CarInterface
if os.path.exists(BASEDIR + '/' + path.replace('.', '/') + '/carstate.py'):
@ -65,10 +65,10 @@ def _get_interface_names():
for car_folder in [x[0] for x in os.walk(BASEDIR + '/selfdrive/car')]:
try:
brand_name = car_folder.split('/')[-1]
model_names = __import__('selfdrive.car.%s.values' % brand_name, fromlist=['CAR']).CAR
model_names = __import__(f'selfdrive.car.{brand_name}.values', fromlist=['CAR']).CAR
model_names = [getattr(model_names, c) for c in model_names.__dict__.keys() if not c.startswith("__")]
brand_names[brand_name] = model_names
except (ImportError, IOError):
except (ImportError, OSError):
pass
return brand_names
@ -131,7 +131,7 @@ def fingerprint(logcan, sendcan):
for b in candidate_cars:
# Ignore extended messages and VIN query response.
if can.src == b and can.address < 0x800 and can.address not in [0x7df, 0x7e0, 0x7e8]:
if can.src == b and can.address < 0x800 and can.address not in (0x7df, 0x7e0, 0x7e8):
candidate_cars[b] = eliminate_incompatible_cars(can, candidate_cars[b])
# if we only have one car choice and the time since we got our first

@ -1,3 +1,4 @@
from cereal import car
from selfdrive.car import apply_toyota_steer_torque_limits
from selfdrive.car.chrysler.chryslercan import create_lkas_hud, create_lkas_command, \
create_wheel_buttons
@ -20,9 +21,8 @@ class CarController():
# this seems needed to avoid steering faults and to force the sync with the EPS counter
frame = CS.lkas_counter
if self.prev_frame == frame:
return []
return car.CarControl.Actuators.new_message(), []
# *** compute control surfaces ***
# steer torque
new_steer = int(round(actuators.steer * CarControllerParams.STEER_MAX))
apply_steer = apply_toyota_steer_torque_limits(new_steer, self.apply_steer_last,
@ -67,4 +67,7 @@ class CarController():
self.ccframe += 1
self.prev_frame = frame
return can_sends
new_actuators = actuators.copy()
new_actuators.steer = apply_steer / CarControllerParams.STEER_MAX
return new_actuators, can_sends

@ -52,7 +52,7 @@ class CarState(CarStateBase):
ret.cruiseState.available = ret.cruiseState.enabled # FIXME: for now same as enabled
ret.cruiseState.speed = cp.vl["DASHBOARD"]["ACC_SPEED_CONFIG_KPH"] * CV.KPH_TO_MS
# CRUISE_STATE is a three bit msg, 0 is off, 1 and 2 are Non-ACC mode, 3 and 4 are ACC mode, find if there are other states too
ret.cruiseState.nonAdaptive = cp.vl["DASHBOARD"]["CRUISE_STATE"] in [1, 2]
ret.cruiseState.nonAdaptive = cp.vl["DASHBOARD"]["CRUISE_STATE"] in (1, 2)
ret.steeringTorque = cp.vl["EPS_STATUS"]["TORQUE_DRIVER"]
ret.steeringTorqueEps = cp.vl["EPS_STATUS"]["TORQUE_MOTOR"]

@ -8,7 +8,7 @@ VisualAlert = car.CarControl.HUDControl.VisualAlert
def create_lkas_hud(packer, gear, lkas_active, hud_alert, hud_count, lkas_car_model):
# LKAS_HUD 0x2a6 (678) Controls what lane-keeping icon is displayed.
if hud_alert in [VisualAlert.steerRequired, VisualAlert.ldw]:
if hud_alert in (VisualAlert.steerRequired, VisualAlert.ldw):
msg = b'\x00\x00\x00\x03\x00\x00\x00\x00'
return make_can_msg(0x2a6, msg, 0)

@ -78,8 +78,6 @@ class CarInterface(CarInterfaceBase):
def apply(self, c):
if (self.CS.frame == -1):
return [] # if we haven't seen a frame 220, then do not update.
return car.CarControl.Actuators.new_message(), [] # if we haven't seen a frame 220, then do not update.
can_sends = self.CC.update(c.enabled, self.CS, c.actuators, c.cruiseControl.cancel, c.hudControl.visualAlert)
return can_sends
return self.CC.update(c.enabled, self.CS, c.actuators, c.cruiseControl.cancel, c.hudControl.visualAlert)

@ -11,7 +11,7 @@ def get_attr_from_cars(attr, result=dict, combine_brands=True):
for car_folder in [x[0] for x in os.walk(BASEDIR + '/selfdrive/car')]:
try:
car_name = car_folder.split('/')[-1]
values = __import__('selfdrive.car.%s.values' % car_name, fromlist=[attr])
values = __import__(f'selfdrive.car.{car_name}.values', fromlist=[attr])
if hasattr(values, attr):
attr_values = getattr(values, attr)
else:
@ -28,7 +28,7 @@ def get_attr_from_cars(attr, result=dict, combine_brands=True):
elif isinstance(attr_values, list):
result += attr_values
except (ImportError, IOError):
except (ImportError, OSError):
pass
return result

@ -22,7 +22,7 @@ class CarController():
def update(self, enabled, CS, frame, actuators, visual_alert, pcm_cancel):
can_sends = []
steer_alert = visual_alert in [VisualAlert.steerRequired, VisualAlert.ldw]
steer_alert = visual_alert in (VisualAlert.steerRequired, VisualAlert.ldw)
apply_steer = actuators.steer
@ -32,7 +32,7 @@ class CarController():
if (frame % 3) == 0:
curvature = self.vehicle_model.calc_curvature(actuators.steeringAngleDeg*math.pi/180., CS.out.vEgo)
curvature = self.vehicle_model.calc_curvature(math.radians(actuators.steeringAngleDeg), CS.out.vEgo, 0.0)
# The use of the toggle below is handy for trying out the various LKAS modes
if TOGGLE_DEBUG:
@ -83,4 +83,4 @@ class CarController():
self.main_on_last = CS.out.cruiseState.available
self.steer_alert_last = steer_alert
return can_sends
return actuators, can_sends

@ -25,7 +25,7 @@ class CarState(CarStateBase):
ret.steeringPressed = not cp.vl["Lane_Keep_Assist_Status"]["LaHandsOff_B_Actl"]
ret.steerError = cp.vl["Lane_Keep_Assist_Status"]["LaActDeny_B_Actl"] == 1
ret.cruiseState.speed = cp.vl["Cruise_Status"]["Set_Speed"] * CV.MPH_TO_MS
ret.cruiseState.enabled = not (cp.vl["Cruise_Status"]["Cruise_State"] in [0, 3])
ret.cruiseState.enabled = not (cp.vl["Cruise_Status"]["Cruise_State"] in (0, 3))
ret.cruiseState.available = cp.vl["Cruise_Status"]["Cruise_State"] != 0
ret.gas = cp.vl["EngineData_14"]["ApedPosScal_Pc_Actl"] / 100.
ret.gasPressed = ret.gas > 1e-6

@ -6,7 +6,7 @@ def create_steer_command(packer, angle_cmd, enabled, lkas_state, angle_steers, c
"""Creates a CAN message for the Ford Steer Command."""
#if enabled and lkas available:
if enabled and lkas_state in [2, 3]: # and (frame % 500) >= 3:
if enabled and lkas_state in (2, 3): # and (frame % 500) >= 3:
action = lkas_action
else:
action = 0xf

@ -51,7 +51,7 @@ class CarInterface(CarInterfaceBase):
# events
events = self.create_common_events(ret)
if self.CS.lkas_state not in [2, 3] and ret.vEgo > 13. * CV.MPH_TO_MS and ret.cruiseState.enabled:
if self.CS.lkas_state not in (2, 3) and ret.vEgo > 13. * CV.MPH_TO_MS and ret.cruiseState.enabled:
events.add(car.CarEvent.EventName.steerTempUnavailable)
ret.events = events.to_msg()
@ -63,8 +63,8 @@ class CarInterface(CarInterfaceBase):
# to be called @ 100hz
def apply(self, c):
can_sends = self.CC.update(c.enabled, self.CS, self.frame, c.actuators,
ret = self.CC.update(c.enabled, self.CS, self.frame, c.actuators,
c.hudControl.visualAlert, c.cruiseControl.cancel)
self.frame += 1
return can_sends
return ret

@ -84,8 +84,21 @@ NISSAN_VERSION_RESPONSE_STANDARD = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIF
NISSAN_RX_OFFSET = 0x20
SUBARU_VERSION_REQUEST = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \
p16(uds.DATA_IDENTIFIER_TYPE.APPLICATION_DATA_IDENTIFICATION)
SUBARU_VERSION_RESPONSE = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER + 0x40]) + \
p16(uds.DATA_IDENTIFIER_TYPE.APPLICATION_DATA_IDENTIFICATION)
# brand, request, response, response offset
REQUESTS = [
# Subaru
(
"subaru",
[TESTER_PRESENT_REQUEST, SUBARU_VERSION_REQUEST],
[TESTER_PRESENT_RESPONSE, SUBARU_VERSION_RESPONSE],
DEFAULT_RX_OFFSET,
),
# Hyundai
(
"hyundai",
@ -221,7 +234,7 @@ def match_fw_to_car_fuzzy(fw_versions_dict, log=True, exclude=None):
if match_count >= 2:
if log:
cloudlog.error(f"Fingerprinted {candidate} using fuzzy match. {match_count} matching ECUs")
return set([candidate])
return {candidate}
else:
return set()
@ -240,11 +253,11 @@ def match_fw_to_car_exact(fw_versions_dict):
addr = ecu[1:]
found_version = fw_versions_dict.get(addr, None)
ESSENTIAL_ECUS = [Ecu.engine, Ecu.eps, Ecu.esp, Ecu.fwdRadar, Ecu.fwdCamera, Ecu.vsa]
if ecu_type == Ecu.esp and candidate in [TOYOTA.RAV4, TOYOTA.COROLLA, TOYOTA.HIGHLANDER, TOYOTA.SIENNA, TOYOTA.LEXUS_IS] and found_version is None:
if ecu_type == Ecu.esp and candidate in (TOYOTA.RAV4, TOYOTA.COROLLA, TOYOTA.HIGHLANDER, TOYOTA.SIENNA, TOYOTA.LEXUS_IS) and found_version is None:
continue
# On some Toyota models, the engine can show on two different addresses
if ecu_type == Ecu.engine and candidate in [TOYOTA.CAMRY, TOYOTA.COROLLA_TSS2, TOYOTA.CHR, TOYOTA.LEXUS_IS] and found_version is None:
if ecu_type == Ecu.engine and candidate in (TOYOTA.CAMRY, TOYOTA.COROLLA_TSS2, TOYOTA.CHR, TOYOTA.LEXUS_IS) and found_version is None:
continue
# Ignore non essential ecus
@ -362,7 +375,7 @@ if __name__ == "__main__":
print("Getting vin...")
addr, vin = get_vin(logcan, sendcan, 1, retry=10, debug=args.debug)
print(f"VIN: {vin}")
print("Getting VIN took %.3f s" % (time.time() - t))
print(f"Getting VIN took {time.time() - t:.3f} s")
print()
t = time.time()
@ -379,4 +392,4 @@ if __name__ == "__main__":
print()
print("Possible matches:", candidates)
print("Getting fw took %.3f s" % (time.time() - t))
print(f"Getting fw took {time.time() - t:.3f} s")

@ -14,6 +14,9 @@ class CarController():
def __init__(self, dbc_name, CP, VM):
self.start_time = 0.
self.apply_steer_last = 0
self.apply_gas = 0
self.apply_brake = 0
self.lka_steering_cmd_counter_last = -1
self.lka_icon_status_last = (False, False)
self.steer_rate_limited = False
@ -53,22 +56,22 @@ class CarController():
can_sends.append(gmcan.create_steering_control(self.packer_pt, CanBus.POWERTRAIN, apply_steer, idx, lkas_enabled))
if not enabled:
# Stock ECU sends max regen when not enabled.
apply_gas = P.MAX_ACC_REGEN
apply_brake = 0
else:
apply_gas = int(round(interp(actuators.accel, P.GAS_LOOKUP_BP, P.GAS_LOOKUP_V)))
apply_brake = int(round(interp(actuators.accel, P.BRAKE_LOOKUP_BP, P.BRAKE_LOOKUP_V)))
# Gas/regen and brakes - all at 25Hz
if (frame % 4) == 0:
if not enabled:
# Stock ECU sends max regen when not enabled.
self.apply_gas = P.MAX_ACC_REGEN
self.apply_brake = 0
else:
self.apply_gas = int(round(interp(actuators.accel, P.GAS_LOOKUP_BP, P.GAS_LOOKUP_V)))
self.apply_brake = int(round(interp(actuators.accel, P.BRAKE_LOOKUP_BP, P.BRAKE_LOOKUP_V)))
idx = (frame // 4) % 4
at_full_stop = enabled and CS.out.standstill
near_stop = enabled and (CS.out.vEgo < P.NEAR_STOP_BRAKE_PHASE)
can_sends.append(gmcan.create_friction_brake_command(self.packer_ch, CanBus.CHASSIS, apply_brake, idx, near_stop, at_full_stop))
can_sends.append(gmcan.create_gas_regen_command(self.packer_pt, CanBus.POWERTRAIN, apply_gas, idx, enabled, at_full_stop))
can_sends.append(gmcan.create_friction_brake_command(self.packer_ch, CanBus.CHASSIS, self.apply_brake, idx, near_stop, at_full_stop))
can_sends.append(gmcan.create_gas_regen_command(self.packer_pt, CanBus.POWERTRAIN, self.apply_gas, idx, enabled, at_full_stop))
# Send dashboard UI commands (ACC status), 25hz
if (frame % 4) == 0:
@ -102,8 +105,13 @@ class CarController():
lka_critical = lka_active and abs(actuators.steer) > 0.9
lka_icon_status = (lka_active, lka_critical)
if frame % P.CAMERA_KEEPALIVE_STEP == 0 or lka_icon_status != self.lka_icon_status_last:
steer_alert = hud_alert in [VisualAlert.steerRequired, VisualAlert.ldw]
steer_alert = hud_alert in (VisualAlert.steerRequired, VisualAlert.ldw)
can_sends.append(gmcan.create_lka_icon_command(CanBus.SW_GMLAN, lka_active, lka_critical, steer_alert))
self.lka_icon_status_last = lka_icon_status
return can_sends
new_actuators = actuators.copy()
new_actuators.steer = self.apply_steer_last / P.STEER_MAX
new_actuators.gas = self.apply_gas
new_actuators.brake = self.apply_brake
return new_actuators, can_sends

@ -36,7 +36,7 @@ class CarState(CarStateBase):
if ret.brake < 10/0xd0:
ret.brake = 0.
ret.gas = pt_cp.vl["AcceleratorPedal"]["AcceleratorPedal"] / 254.
ret.gas = pt_cp.vl["AcceleratorPedal2"]["AcceleratorPedal2"] / 254.
ret.gasPressed = ret.gas > 1e-5
ret.steeringAngleDeg = pt_cp.vl["PSCMSteeringAngle"]["SteeringWheelAngle"]
@ -90,7 +90,7 @@ class CarState(CarStateBase):
("LeftSeatBelt", "BCMDoorBeltStatus", 0),
("RightSeatBelt", "BCMDoorBeltStatus", 0),
("TurnSignals", "BCMTurnSignals", 0),
("AcceleratorPedal", "AcceleratorPedal", 0),
("AcceleratorPedal2", "AcceleratorPedal2", 0),
("CruiseState", "AcceleratorPedal2", 0),
("ACCButtons", "ASCMSteeringButton", CruiseButtons.UNPRESS),
("SteeringWheelAngle", "PSCMSteeringAngle", 0),
@ -117,7 +117,6 @@ class CarState(CarStateBase):
("EPBStatus", 20),
("EBCMWheelSpdFront", 20),
("EBCMWheelSpdRear", 20),
("AcceleratorPedal", 33),
("AcceleratorPedal2", 33),
("ASCMSteeringButton", 33),
("ECMEngineStatus", 100),

@ -44,6 +44,11 @@ class CarInterface(CarInterfaceBase):
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.gm)]
ret.pcmCruise = False # stock cruise control is kept off
# 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/test/test_routes, we can remove it from this list.
ret.dashcamOnly = candidate in {CAR.CADILLAC_ATS, CAR.HOLDEN_ASTRA, CAR.MALIBU}
# Presence of a camera on the object bus is ok.
# Have to go to read_only if ASCM is online (ACC-enabled cars),
# or camera is on powertrain bus (LKA cars without ACC).
@ -198,7 +203,7 @@ class CarInterface(CarInterfaceBase):
# handle button presses
for b in ret.buttonEvents:
# do enable on both accel and decel buttons
if b.type in [ButtonType.accelCruise, ButtonType.decelCruise] and not b.pressed:
if b.type in (ButtonType.accelCruise, ButtonType.decelCruise) and not b.pressed:
events.add(EventName.buttonEnable)
# do disable on button down
if b.type == ButtonType.cancel and b.pressed:
@ -212,7 +217,8 @@ class CarInterface(CarInterfaceBase):
return self.CS.out
def apply(self, c):
hud_v_cruise = c.hudControl.setSpeed
hud_control = c.hudControl
hud_v_cruise = hud_control.setSpeed
if hud_v_cruise > 70:
hud_v_cruise = 0
@ -220,10 +226,10 @@ class CarInterface(CarInterfaceBase):
# In GM, PCM faults out if ACC command overlaps user gas.
enabled = c.enabled and not self.CS.out.gasPressed
can_sends = self.CC.update(enabled, self.CS, self.frame,
c.actuators,
hud_v_cruise, c.hudControl.lanesVisible,
c.hudControl.leadVisible, c.hudControl.visualAlert)
ret = self.CC.update(enabled, self.CS, self.frame,
c.actuators,
hud_v_cruise, hud_control.lanesVisible,
hud_control.leadVisible, hud_control.visualAlert)
self.frame += 1
return can_sends
return ret

@ -1,5 +1,4 @@
#!/usr/bin/env python3
from __future__ import print_function
import math
from cereal import car
from opendbc.can.parser import CANParser

@ -83,7 +83,7 @@ def process_hud_alert(hud_alert):
# priority is: FCW, steer required, all others
if hud_alert == VisualAlert.fcw:
fcw_display = VISUAL_HUD[hud_alert.raw]
elif hud_alert in [VisualAlert.steerRequired, VisualAlert.ldw]:
elif hud_alert in (VisualAlert.steerRequired, VisualAlert.ldw):
steer_required = VISUAL_HUD[hud_alert.raw]
else:
acc_alert = VISUAL_HUD[hud_alert.raw]
@ -105,6 +105,11 @@ class CarController():
self.last_pump_ts = 0.
self.packer = CANPacker(dbc_name)
self.accel = 0
self.speed = 0
self.gas = 0
self.brake = 0
self.params = CarControllerParams(CP)
def update(self, enabled, active, CS, frame, actuators, pcm_cancel_cmd,
@ -163,7 +168,6 @@ class CarController():
lkas_active, CS.CP.carFingerprint, idx, CS.CP.openpilotLongitudinalControl))
stopping = actuators.longControlState == LongCtrlState.stopping
starting = actuators.longControlState == LongCtrlState.starting
# wind brake from air resistance decel at high speed
wind_brake = interp(CS.out.vEgo, [0.0, 2.3, 35.0], [0.001, 0.002, 0.15])
@ -211,10 +215,9 @@ class CarController():
ts = frame * DT_CTRL
if CS.CP.carFingerprint in HONDA_BOSCH:
accel = clip(accel, P.BOSCH_ACCEL_MIN, P.BOSCH_ACCEL_MAX)
bosch_gas = interp(accel, P.BOSCH_GAS_LOOKUP_BP, P.BOSCH_GAS_LOOKUP_V)
can_sends.extend(hondacan.create_acc_commands(self.packer, enabled, active, accel, bosch_gas, idx, stopping, starting, CS.CP.carFingerprint))
self.accel = clip(accel, P.BOSCH_ACCEL_MIN, P.BOSCH_ACCEL_MAX)
self.gas = interp(accel, P.BOSCH_GAS_LOOKUP_BP, P.BOSCH_GAS_LOOKUP_V)
can_sends.extend(hondacan.create_acc_commands(self.packer, enabled, active, accel, self.gas, idx, stopping, CS.CP.carFingerprint))
else:
apply_brake = clip(self.brake_last - wind_brake, 0.0, 1.0)
apply_brake = int(clip(apply_brake * P.NIDEC_BRAKE_MAX, 0, P.NIDEC_BRAKE_MAX - 1))
@ -224,6 +227,7 @@ class CarController():
can_sends.append(hondacan.create_brake_command(self.packer, apply_brake, pump_on,
pcm_override, pcm_cancel_cmd, fcw_display, idx, CS.CP.carFingerprint, CS.stock_brake))
self.apply_brake_last = apply_brake
self.brake = apply_brake / P.NIDEC_BRAKE_MAX
if CS.CP.enableGasInterceptor:
# way too aggressive at low speed without this
@ -233,17 +237,28 @@ class CarController():
# Sending non-zero gas when OP is not enabled will cause the PCM not to respond to throttle as expected
# when you do enable.
if active:
apply_gas = clip(gas_mult * (gas - brake + wind_brake*3/4), 0., 1.)
self.gas = clip(gas_mult * (gas - brake + wind_brake*3/4), 0., 1.)
else:
apply_gas = 0.0
can_sends.append(create_gas_interceptor_command(self.packer, apply_gas, idx))
hud = HUDData(int(pcm_accel), int(round(hud_v_cruise)), hud_car,
hud_lanes, fcw_display, acc_alert, steer_required)
self.gas = 0.0
can_sends.append(create_gas_interceptor_command(self.packer, self.gas, idx))
# Send dashboard UI commands.
if (frame % 10) == 0:
idx = (frame//10) % 4
hud = HUDData(int(pcm_accel), int(round(hud_v_cruise)), hud_car,
hud_lanes, fcw_display, acc_alert, steer_required)
can_sends.extend(hondacan.create_ui_commands(self.packer, CS.CP, pcm_speed, hud, CS.is_metric, idx, CS.stock_hud))
return can_sends
if (CS.CP.openpilotLongitudinalControl) and (CS.CP.carFingerprint not in HONDA_BOSCH):
self.speed = pcm_speed
if not CS.CP.enableGasInterceptor:
self.gas = pcm_accel / 0xc6
new_actuators = actuators.copy()
new_actuators.speed = self.speed
new_actuators.accel = self.accel
new_actuators.gas = self.gas
new_actuators.brake = self.brake
return new_actuators, can_sends

@ -107,7 +107,7 @@ def get_can_signals(CP, gearbox_msg, main_on_sig_msg):
else:
checks += [("CRUISE_PARAMS", 50)]
if CP.carFingerprint in (CAR.ACCORD, CAR.ACCORD_2021, CAR.ACCORDH, CAR.ACCORDH_2021, CAR.CIVIC_BOSCH, CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_HYBRID, CAR.INSIGHT, CAR.ACURA_RDX_3G, CAR.HONDA_E):
if CP.carFingerprint in (CAR.ACCORD, CAR.ACCORDH, CAR.CIVIC_BOSCH, CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_HYBRID, CAR.INSIGHT, CAR.ACURA_RDX_3G, CAR.HONDA_E):
signals += [("DRIVERS_DOOR_OPEN", "SCM_FEEDBACK", 1)]
elif CP.carFingerprint == CAR.ODYSSEY_CHN:
signals += [("DRIVERS_DOOR_OPEN", "SCM_BUTTONS", 1)]
@ -185,7 +185,7 @@ class CarState(CarStateBase):
# ******************* parse out can *******************
# TODO: find wheels moving bit in dbc
if self.CP.carFingerprint in (CAR.ACCORD, CAR.ACCORD_2021, CAR.ACCORDH, CAR.ACCORDH_2021, CAR.CIVIC_BOSCH, CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_HYBRID, CAR.INSIGHT, CAR.ACURA_RDX_3G, CAR.HONDA_E):
if self.CP.carFingerprint in (CAR.ACCORD, CAR.ACCORDH, CAR.CIVIC_BOSCH, CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_HYBRID, CAR.INSIGHT, CAR.ACURA_RDX_3G, CAR.HONDA_E):
ret.standstill = cp.vl["ENGINE_DATA"]["XMISSION_SPEED"] < 0.1
ret.doorOpen = bool(cp.vl["SCM_FEEDBACK"]["DRIVERS_DOOR_OPEN"])
elif self.CP.carFingerprint == CAR.ODYSSEY_CHN:
@ -201,11 +201,11 @@ class CarState(CarStateBase):
ret.seatbeltUnlatched = bool(cp.vl["SEATBELT_STATUS"]["SEATBELT_DRIVER_LAMP"] or not cp.vl["SEATBELT_STATUS"]["SEATBELT_DRIVER_LATCHED"])
steer_status = self.steer_status_values[cp.vl["STEER_STATUS"]["STEER_STATUS"]]
ret.steerError = steer_status not in ["NORMAL", "NO_TORQUE_ALERT_1", "NO_TORQUE_ALERT_2", "LOW_SPEED_LOCKOUT", "TMP_FAULT"]
ret.steerError = steer_status not in ("NORMAL", "NO_TORQUE_ALERT_1", "NO_TORQUE_ALERT_2", "LOW_SPEED_LOCKOUT", "TMP_FAULT")
# NO_TORQUE_ALERT_2 can be caused by bump OR steering nudge from driver
self.steer_not_allowed = steer_status not in ["NORMAL", "NO_TORQUE_ALERT_2"]
self.steer_not_allowed = steer_status not in ("NORMAL", "NO_TORQUE_ALERT_2")
# LOW_SPEED_LOCKOUT is not worth a warning
ret.steerWarning = steer_status not in ["NORMAL", "LOW_SPEED_LOCKOUT", "NO_TORQUE_ALERT_2"]
ret.steerWarning = steer_status not in ("NORMAL", "LOW_SPEED_LOCKOUT", "NO_TORQUE_ALERT_2")
if not self.CP.openpilotLongitudinalControl:
self.brake_error = 0
@ -236,7 +236,7 @@ class CarState(CarStateBase):
250, cp.vl["SCM_FEEDBACK"]["LEFT_BLINKER"], cp.vl["SCM_FEEDBACK"]["RIGHT_BLINKER"])
ret.brakeHoldActive = cp.vl["VSA_STATUS"]["BRAKE_HOLD_ACTIVE"] == 1
if self.CP.carFingerprint in (CAR.CIVIC, CAR.ODYSSEY, CAR.ODYSSEY_CHN, CAR.CRV_5G, CAR.ACCORD, CAR.ACCORD_2021, CAR.ACCORDH, CAR.ACCORDH_2021, CAR.CIVIC_BOSCH,
if self.CP.carFingerprint in (CAR.CIVIC, CAR.ODYSSEY, CAR.ODYSSEY_CHN, CAR.CRV_5G, CAR.ACCORD, CAR.ACCORDH, CAR.CIVIC_BOSCH,
CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_HYBRID, CAR.INSIGHT, CAR.ACURA_RDX_3G, CAR.HONDA_E):
self.park_brake = cp.vl["EPB_STATUS"]["EPB_STATE"] != 0
else:

@ -43,7 +43,7 @@ def create_brake_command(packer, apply_brake, pump_on, pcm_override, pcm_cancel_
return packer.make_can_msg("BRAKE_COMMAND", bus, values, idx)
def create_acc_commands(packer, enabled, active, accel, gas, idx, stopping, starting, car_fingerprint):
def create_acc_commands(packer, enabled, active, accel, gas, idx, stopping, car_fingerprint):
commands = []
bus = get_pt_bus(car_fingerprint)
min_gas_accel = CarControllerParams.BOSCH_GAS_LOOKUP_BP[0]
@ -53,7 +53,7 @@ def create_acc_commands(packer, enabled, active, accel, gas, idx, stopping, star
accel_command = accel if active else 0
braking = 1 if active and accel < min_gas_accel else 0
standstill = 1 if active and stopping else 0
standstill_release = 1 if active and starting else 0
standstill_release = 1 if active and not stopping else 0
acc_control_values = {
# setting CONTROL_ON causes car to set POWERTRAIN_DATA->ACC_STATUS = 1

@ -114,7 +114,7 @@ class CarInterface(CarInterfaceBase):
tire_stiffness_factor = 1.
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]]
elif candidate in (CAR.ACCORD, CAR.ACCORD_2021, CAR.ACCORDH, CAR.ACCORDH_2021):
elif candidate in (CAR.ACCORD, CAR.ACCORDH):
stop_and_go = True
ret.mass = 3279. * CV.LB_TO_KG + STD_CARGO_KG
ret.wheelbase = 2.83
@ -227,7 +227,7 @@ class CarInterface(CarInterfaceBase):
ret.centerToFront = ret.wheelbase * 0.41
ret.steerRatio = 11.95 # as spec
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 3840], [0, 3840]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.18]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2], [0.06]]
tire_stiffness_factor = 0.677
elif candidate == CAR.ODYSSEY:
@ -301,7 +301,7 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.18]] # TODO: can probably use some tuning
else:
raise ValueError("unsupported car %s" % candidate)
raise ValueError(f"unsupported car {candidate}")
# These cars use alternate user brake msg (0x1BE)
if candidate in HONDA_BOSCH_ALT_BRAKE_SIGNAL:
@ -350,7 +350,6 @@ class CarInterface(CarInterfaceBase):
ret = self.CS.update(self.cp, self.cp_cam, self.cp_body)
ret.canValid = self.cp.can_valid and self.cp_cam.can_valid and (self.cp_body is None or self.cp_body.can_valid)
ret.yawRate = self.VM.yaw_rate(ret.steeringAngleDeg * CV.DEG_TO_RAD, ret.vEgo)
buttonEvents = []
@ -417,7 +416,7 @@ class CarInterface(CarInterfaceBase):
for b in ret.buttonEvents:
# do enable on both accel and decel buttons
if b.type in [ButtonType.accelCruise, ButtonType.decelCruise] and not b.pressed:
if b.type in (ButtonType.accelCruise, ButtonType.decelCruise) and not b.pressed:
if not self.CP.pcmCruise:
events.add(EventName.buttonEnable)
@ -433,18 +432,19 @@ class CarInterface(CarInterfaceBase):
# pass in a car.CarControl
# to be called @ 100hz
def apply(self, c):
if c.hudControl.speedVisible:
hud_v_cruise = c.hudControl.setSpeed * CV.MS_TO_KPH
hud_control = c.hudControl
if hud_control.speedVisible:
hud_v_cruise = hud_control.setSpeed * CV.MS_TO_KPH
else:
hud_v_cruise = 255
can_sends = self.CC.update(c.enabled, c.active, self.CS, self.frame,
c.actuators,
c.cruiseControl.cancel,
hud_v_cruise,
c.hudControl.lanesVisible,
hud_show_car=c.hudControl.leadVisible,
hud_alert=c.hudControl.visualAlert)
ret = self.CC.update(c.enabled, c.active, self.CS, self.frame,
c.actuators,
c.cruiseControl.cancel,
hud_v_cruise,
hud_control.lanesVisible,
hud_show_car=hud_control.leadVisible,
hud_alert=hud_control.visualAlert)
self.frame += 1
return can_sends
return ret

@ -66,8 +66,6 @@ VISUAL_HUD = {
class CAR:
ACCORD = "HONDA ACCORD 2018"
ACCORDH = "HONDA ACCORD HYBRID 2018"
ACCORD_2021 = "HONDA ACCORD 2021"
ACCORDH_2021 = "HONDA ACCORD HYBRID 2021"
CIVIC = "HONDA CIVIC 2016"
CIVIC_BOSCH = "HONDA CIVIC (BOSCH) 2019"
CIVIC_BOSCH_DIESEL = "HONDA CIVIC SEDAN 1.6 DIESEL 2019"
@ -105,7 +103,9 @@ FW_VERSIONS = {
b'37805-6A0-A750\x00\x00',
b'37805-6A0-A840\x00\x00',
b'37805-6A0-A850\x00\x00',
b'37805-6A0-AF30\x00\x00',
b'37805-6A0-AG30\x00\x00',
b'37805-6B2-C520\x00\x00',
b'37805-6A0-C540\x00\x00',
b'37805-6A1-H650\x00\x00',
b'37805-6B2-A550\x00\x00',
@ -131,6 +131,7 @@ FW_VERSIONS = {
b'28101-6A7-A410\x00\x00',
b'28101-6A7-A510\x00\x00',
b'28101-6A7-A610\x00\x00',
b'28101-6A7-A710\x00\x00',
b'28101-6A9-H140\x00\x00',
b'28101-6A9-H420\x00\x00',
b'28102-6B8-A560\x00\x00',
@ -155,10 +156,12 @@ FW_VERSIONS = {
b'57114-TVA-B040\x00\x00',
b'57114-TVA-B050\x00\x00',
b'57114-TVA-B060\x00\x00',
b'57114-TVA-B530\x00\x00',
b'57114-TVA-C040\x00\x00',
b'57114-TVA-C050\x00\x00',
b'57114-TVA-C060\x00\x00',
b'57114-TVA-C530\x00\x00',
b'57114-TVA-E520\x00\x00',
b'57114-TVE-H250\x00\x00',
],
(Ecu.eps, 0x18da30f1, None): [
@ -166,6 +169,7 @@ FW_VERSIONS = {
b'39990-TVA-A140\x00\x00',
b'39990-TVA-A150\x00\x00',
b'39990-TVA-A160\x00\x00',
b'39990-TVA-A340\x00\x00',
b'39990-TVA-X030\x00\x00',
b'39990-TVA-X040\x00\x00',
b'39990-TVA,A150\x00\x00',
@ -173,6 +177,7 @@ FW_VERSIONS = {
],
(Ecu.unknown, 0x18da3af1, None): [
b'39390-TVA-A020\x00\x00',
b'39390-TVA-A120\x00\x00',
],
(Ecu.srs, 0x18da53f1, None): [
b'77959-TBX-H230\x00\x00',
@ -191,6 +196,7 @@ FW_VERSIONS = {
b'78109-TVA-A120\x00\x00',
b'78109-TVA-A210\x00\x00',
b'78109-TVA-A220\x00\x00',
b'78109-TVA-A230\x00\x00',
b'78109-TVA-A310\x00\x00',
b'78109-TVA-C010\x00\x00',
b'78109-TVA-L010\x00\x00',
@ -203,6 +209,7 @@ FW_VERSIONS = {
b'78109-TVC-A130\x00\x00',
b'78109-TVC-A210\x00\x00',
b'78109-TVC-A220\x00\x00',
b'78109-TVC-A230\x00\x00',
b'78109-TVC-C010\x00\x00',
b'78109-TVC-C110\x00\x00',
b'78109-TVC-L010\x00\x00',
@ -214,12 +221,15 @@ FW_VERSIONS = {
],
(Ecu.hud, 0x18da61f1, None): [
b'78209-TVA-A010\x00\x00',
b'78209-TVA-A110\x00\x00',
],
(Ecu.fwdRadar, 0x18dab0f1, None): [
b'36802-TBX-H140\x00\x00',
b'36802-TVA-A150\x00\x00',
b'36802-TVA-A160\x00\x00',
b'36802-TVA-A170\x00\x00',
b'36802-TVA-A330\x00\x00',
b'36802-TVC-A330\x00\x00',
b'36802-TVE-H070\x00\x00',
b'36802-TWA-A070\x00\x00',
b'36802-TWA-A080\x00\x00',
@ -227,6 +237,7 @@ FW_VERSIONS = {
(Ecu.fwdCamera, 0x18dab5f1, None): [
b'36161-TBX-H130\x00\x00',
b'36161-TVA-A060\x00\x00',
b'36161-TVA-A330\x00\x00',
b'36161-TVC-A330\x00\x00',
b'36161-TVE-H050\x00\x00',
b'36161-TWA-A070\x00\x00',
@ -246,6 +257,7 @@ FW_VERSIONS = {
(Ecu.vsa, 0x18da28f1, None): [
b'57114-TWA-A040\x00\x00',
b'57114-TWA-A050\x00\x00',
b'57114-TWA-A530\x00\x00',
b'57114-TWA-B520\x00\x00',
],
(Ecu.srs, 0x18da53f1, None): [
@ -258,6 +270,7 @@ FW_VERSIONS = {
b'78109-TWA-A030\x00\x00',
b'78109-TWA-A110\x00\x00',
b'78109-TWA-A120\x00\x00',
b'78109-TWA-A130\x00\x00',
b'78109-TWA-A210\x00\x00',
b'78109-TWA-A220\x00\x00',
b'78109-TWA-A230\x00\x00',
@ -273,95 +286,18 @@ FW_VERSIONS = {
],
(Ecu.fwdCamera, 0x18dab5f1, None): [
b'36161-TWA-A070\x00\x00',
b'36161-TWA-A330\x00\x00',
],
(Ecu.fwdRadar, 0x18dab0f1, None): [
b'36802-TWA-A070\x00\x00',
b'36802-TWA-A080\x00\x00',
b'36802-TWA-A330\x00\x00',
],
(Ecu.eps, 0x18da30f1, None): [
b'39990-TVA-A160\x00\x00',
b'39990-TVA-A150\x00\x00',
],
},
CAR.ACCORD_2021: {
(Ecu.programmedFuelInjection, 0x18da10f1, None): [
b'37805-6A0-AF30\x00\x00',
b'37805-6B2-C520\x00\x00',
],
(Ecu.transmission, 0x18da1ef1, None): [
b'28101-6A7-A710\x00\x00',
b'28102-6B8-A700\x00\x00',
],
(Ecu.electricBrakeBooster, 0x18da2bf1, None): [
b'46114-TVA-A320\x00\x00',
],
(Ecu.gateway, 0x18daeff1, None): [
b'38897-TVA-A020\x00\x00',
b'38897-TVA-A240\x00\x00',
],
(Ecu.vsa, 0x18da28f1, None): [
b'57114-TVA-B530\x00\x00',
b'57114-TVA-E520\x00\x00',
],
(Ecu.srs, 0x18da53f1, None): [
b'77959-TVA-L420\x00\x00',
],
(Ecu.combinationMeter, 0x18da60f1, None): [
b'78109-TVA-A230\x00\x00',
b'78109-TVC-A230\x00\x00',
],
(Ecu.hud, 0x18da61f1, None): [
b'78209-TVA-A110\x00\x00',
],
(Ecu.shiftByWire, 0x18da0bf1, None): [
b'54008-TVC-A910\x00\x00',
],
(Ecu.fwdCamera, 0x18dab5f1, None): [
b'36161-TVA-A330\x00\x00',
b'36161-TVC-A330\x00\x00',
],
(Ecu.fwdRadar, 0x18dab0f1, None): [
b'36802-TVA-A330\x00\x00',
b'36802-TVC-A330\x00\x00',
],
(Ecu.eps, 0x18da30f1, None): [
b'39990-TVA-A340\x00\x00',
],
(Ecu.unknown, 0x18da3af1, None): [
b'39390-TVA-A120\x00\x00',
],
},
CAR.ACCORDH_2021: {
(Ecu.gateway, 0x18daeff1, None): [
b'38897-TWD-J020\x00\x00',
],
(Ecu.vsa, 0x18da28f1, None): [
b'57114-TWA-A530\x00\x00',
b'57114-TWA-B520\x00\x00',
],
(Ecu.srs, 0x18da53f1, None): [
b'77959-TWA-L420\x00\x00',
],
(Ecu.combinationMeter, 0x18da60f1, None): [
b'78109-TWA-A030\x00\x00',
b'78109-TWA-A130\x00\x00',
b'78109-TWA-A230\x00\x00',
],
(Ecu.shiftByWire, 0x18da0bf1, None): [
b'54008-TWA-A910\x00\x00',
],
(Ecu.fwdCamera, 0x18dab5f1, None): [
b'36161-TWA-A330\x00\x00',
],
(Ecu.fwdRadar, 0x18dab0f1, None): [
b'36802-TWA-A330\x00\x00',
],
(Ecu.eps, 0x18da30f1, None): [
b'39990-TVA-A340\x00\x00',
],
(Ecu.unknown, 0x18da3af1, None): [
b'39390-TVA-A120\x00\x00',
],
},
CAR.CIVIC: {
(Ecu.programmedFuelInjection, 0x18da10f1, None): [
@ -1419,9 +1355,7 @@ FW_VERSIONS = {
DBC = {
CAR.ACCORD: dbc_dict('honda_accord_2018_can_generated', None),
CAR.ACCORD_2021: dbc_dict('honda_accord_2018_can_generated', None),
CAR.ACCORDH: dbc_dict('honda_accord_2018_can_generated', None),
CAR.ACCORDH_2021: dbc_dict('honda_accord_2018_can_generated', None),
CAR.ACURA_ILX: dbc_dict('acura_ilx_2016_can_generated', 'acura_ilx_2016_nidec'),
CAR.ACURA_RDX: dbc_dict('acura_rdx_2018_can_generated', 'acura_ilx_2016_nidec'),
CAR.ACURA_RDX_3G: dbc_dict('acura_rdx_2020_can_generated', None),
@ -1451,9 +1385,9 @@ STEER_THRESHOLD = {
CAR.CRV_EU: 400,
}
HONDA_NIDEC_ALT_PCM_ACCEL = set([CAR.ODYSSEY])
HONDA_NIDEC_ALT_SCM_MESSAGES = set([CAR.ACURA_ILX, CAR.ACURA_RDX, CAR.CRV, CAR.CRV_EU, CAR.FIT, CAR.FREED, CAR.HRV, CAR.ODYSSEY_CHN,
CAR.PILOT, CAR.PILOT_2019, CAR.PASSPORT, CAR.RIDGELINE])
HONDA_BOSCH = set([CAR.ACCORD, CAR.ACCORD_2021, CAR.ACCORDH, CAR.ACCORDH_2021, CAR.CIVIC_BOSCH, CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_5G,
CAR.CRV_HYBRID, CAR.INSIGHT, CAR.ACURA_RDX_3G, CAR.HONDA_E])
HONDA_BOSCH_ALT_BRAKE_SIGNAL = set([CAR.ACCORD, CAR.ACCORD_2021, CAR.CRV_5G, CAR.ACURA_RDX_3G])
HONDA_NIDEC_ALT_PCM_ACCEL = {CAR.ODYSSEY}
HONDA_NIDEC_ALT_SCM_MESSAGES = {CAR.ACURA_ILX, CAR.ACURA_RDX, CAR.CRV, CAR.CRV_EU, CAR.FIT, CAR.FREED, CAR.HRV, CAR.ODYSSEY_CHN,
CAR.PILOT, CAR.PILOT_2019, CAR.PASSPORT, CAR.RIDGELINE}
HONDA_BOSCH = {CAR.ACCORD, CAR.ACCORDH, CAR.CIVIC_BOSCH, CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_5G,
CAR.CRV_HYBRID, CAR.INSIGHT, CAR.ACURA_RDX_3G, CAR.HONDA_E}
HONDA_BOSCH_ALT_BRAKE_SIGNAL = {CAR.ACCORD, CAR.CRV_5G, CAR.ACURA_RDX_3G}

@ -13,7 +13,7 @@ LongCtrlState = car.CarControl.Actuators.LongControlState
def process_hud_alert(enabled, fingerprint, visual_alert, left_lane,
right_lane, left_lane_depart, right_lane_depart):
sys_warning = (visual_alert in [VisualAlert.steerRequired, VisualAlert.ldw])
sys_warning = (visual_alert in (VisualAlert.steerRequired, VisualAlert.ldw))
# initialize to no line visible
sys_state = 1
@ -28,9 +28,9 @@ def process_hud_alert(enabled, fingerprint, visual_alert, left_lane,
left_lane_warning = 0
right_lane_warning = 0
if left_lane_depart:
left_lane_warning = 1 if fingerprint in [CAR.GENESIS_G90, CAR.GENESIS_G80] else 2
left_lane_warning = 1 if fingerprint in (CAR.GENESIS_G90, CAR.GENESIS_G80) else 2
if right_lane_depart:
right_lane_warning = 1 if fingerprint in [CAR.GENESIS_G90, CAR.GENESIS_G80] else 2
right_lane_warning = 1 if fingerprint in (CAR.GENESIS_G90, CAR.GENESIS_G80) else 2
return sys_warning, sys_state, left_lane_warning, right_lane_warning
@ -44,6 +44,7 @@ class CarController():
self.car_fingerprint = CP.carFingerprint
self.steer_rate_limited = False
self.last_resume_frame = 0
self.accel = 0
def update(self, enabled, CS, frame, actuators, pcm_cancel_cmd, visual_alert, hud_speed,
left_lane, right_lane, left_lane_depart, right_lane_depart):
@ -100,12 +101,13 @@ class CarController():
stopping = (actuators.longControlState == LongCtrlState.stopping)
set_speed_in_units = hud_speed * (CV.MS_TO_MPH if CS.clu11["CF_Clu_SPEED_UNIT"] == 1 else CV.MS_TO_KPH)
can_sends.extend(create_acc_commands(self.packer, enabled, accel, jerk, int(frame / 2), lead_visible, set_speed_in_units, stopping))
self.accel = accel
# 20 Hz LFA MFA message
if frame % 5 == 0 and self.car_fingerprint in [CAR.SONATA, CAR.PALISADE, CAR.IONIQ, CAR.KIA_NIRO_EV, CAR.KIA_NIRO_HEV_2021,
if frame % 5 == 0 and self.car_fingerprint in (CAR.SONATA, CAR.PALISADE, CAR.IONIQ, CAR.KIA_NIRO_EV, CAR.KIA_NIRO_HEV_2021,
CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KIA_CEED, CAR.KIA_SELTOS, CAR.KONA_EV,
CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.SANTA_FE_2022,
CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.GENESIS_G70_2020]:
CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.GENESIS_G70_2020, CAR.SANTA_FE_PHEV_2022):
can_sends.append(create_lfahda_mfc(self.packer, enabled))
# 5 Hz ACC options
@ -116,4 +118,8 @@ class CarController():
if frame % 50 == 0 and CS.CP.openpilotLongitudinalControl:
can_sends.append(create_frt_radar_opt(self.packer))
return can_sends
new_actuators = actuators.copy()
new_actuators.steer = apply_steer / self.p.STEER_MAX
new_actuators.accel = self.accel
return new_actuators, can_sends

@ -16,10 +16,10 @@ def create_lkas11(packer, frame, car_fingerprint, apply_steer, steer_req,
values["CF_Lkas_ActToi"] = steer_req
values["CF_Lkas_MsgCount"] = frame % 0x10
if car_fingerprint in [CAR.SONATA, CAR.PALISADE, CAR.KIA_NIRO_EV, CAR.KIA_NIRO_HEV_2021, CAR.SANTA_FE,
if car_fingerprint in (CAR.SONATA, CAR.PALISADE, CAR.KIA_NIRO_EV, CAR.KIA_NIRO_HEV_2021, CAR.SANTA_FE,
CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KIA_SELTOS, CAR.ELANTRA_2021, CAR.GENESIS_G70_2020,
CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_EV, CAR.KONA_HEV, CAR.SANTA_FE_2022,
CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022]:
CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022):
values["CF_Lkas_LdwsActivemode"] = int(left_lane) + (int(right_lane) << 1)
values["CF_Lkas_LdwsOpt_USM"] = 2

@ -41,11 +41,10 @@ class CarInterface(CarInterfaceBase):
ret.longitudinalTuning.kpV = [0.1]
ret.longitudinalTuning.kiV = [0.0]
ret.stopAccel = 0.0
ret.startAccel = 0.0
ret.longitudinalActuatorDelayUpperBound = 1.0 # s
if candidate in [CAR.SANTA_FE, CAR.SANTA_FE_2022, CAR.SANTA_FE_HEV_2022]:
if candidate in (CAR.SANTA_FE, CAR.SANTA_FE_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022):
ret.lateralTuning.pid.kf = 0.00005
ret.mass = 3982. * CV.LB_TO_KG + STD_CARGO_KG
ret.wheelbase = 2.766
@ -54,7 +53,7 @@ class CarInterface(CarInterfaceBase):
tire_stiffness_factor = 0.82
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[9., 22.], [9., 22.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2, 0.35], [0.05, 0.09]]
elif candidate in [CAR.SONATA, CAR.SONATA_HYBRID]:
elif candidate in (CAR.SONATA, CAR.SONATA_HYBRID):
ret.lateralTuning.pid.kf = 0.00005
ret.mass = 1513. + STD_CARGO_KG
ret.wheelbase = 2.84
@ -77,7 +76,7 @@ class CarInterface(CarInterfaceBase):
tire_stiffness_factor = 0.63
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.3], [0.05]]
elif candidate in [CAR.ELANTRA, CAR.ELANTRA_GT_I30]:
elif candidate in (CAR.ELANTRA, CAR.ELANTRA_GT_I30):
ret.lateralTuning.pid.kf = 0.00006
ret.mass = 1275. + STD_CARGO_KG
ret.wheelbase = 2.7
@ -117,7 +116,7 @@ class CarInterface(CarInterfaceBase):
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]:
elif candidate in (CAR.KONA, CAR.KONA_EV, CAR.KONA_HEV):
ret.lateralTuning.pid.kf = 0.00005
ret.mass = {CAR.KONA_EV: 1685., CAR.KONA_HEV: 1425.}.get(candidate, 1275.) + STD_CARGO_KG
ret.wheelbase = 2.7
@ -125,7 +124,7 @@ class CarInterface(CarInterfaceBase):
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 in [CAR.IONIQ, CAR.IONIQ_EV_LTD, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.IONIQ_HEV_2022]:
elif candidate in (CAR.IONIQ, CAR.IONIQ_EV_LTD, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.IONIQ_HEV_2022):
ret.lateralTuning.pid.kf = 0.00006
ret.mass = 1490. + STD_CARGO_KG # weight per hyundai site https://www.hyundaiusa.com/ioniq-electric/specifications.aspx
ret.wheelbase = 2.7
@ -133,7 +132,7 @@ class CarInterface(CarInterfaceBase):
tire_stiffness_factor = 0.385
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]]
if candidate not in [CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.IONIQ_HEV_2022]:
if candidate not in (CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.IONIQ_HEV_2022):
ret.minSteerSpeed = 32 * CV.MPH_TO_MS
elif candidate == CAR.VELOSTER:
ret.lateralTuning.pid.kf = 0.00005
@ -152,7 +151,7 @@ class CarInterface(CarInterfaceBase):
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_HEV, CAR.KIA_NIRO_HEV_2021]:
elif candidate in (CAR.KIA_NIRO_EV, CAR.KIA_NIRO_HEV, CAR.KIA_NIRO_HEV_2021):
ret.lateralTuning.pid.kf = 0.00006
ret.mass = 1737. + STD_CARGO_KG
ret.wheelbase = 2.7
@ -176,7 +175,7 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.indi.timeConstantV = [1.4]
ret.lateralTuning.indi.actuatorEffectivenessBP = [0.]
ret.lateralTuning.indi.actuatorEffectivenessV = [1.8]
elif candidate in [CAR.KIA_OPTIMA, CAR.KIA_OPTIMA_H]:
elif candidate in (CAR.KIA_OPTIMA, CAR.KIA_OPTIMA_H):
ret.lateralTuning.pid.kf = 0.00005
ret.mass = 3558. * CV.LB_TO_KG
ret.wheelbase = 2.80
@ -327,7 +326,7 @@ class CarInterface(CarInterfaceBase):
for b in ret.buttonEvents:
# do enable on both accel and decel buttons
if b.type in [ButtonType.accelCruise, ButtonType.decelCruise] and not b.pressed:
if b.type in (ButtonType.accelCruise, ButtonType.decelCruise) and not b.pressed:
events.add(EventName.buttonEnable)
# do disable on button down
if b.type == ButtonType.cancel and b.pressed:
@ -347,8 +346,9 @@ class CarInterface(CarInterfaceBase):
return self.CS.out
def apply(self, c):
can_sends = self.CC.update(c.enabled, self.CS, self.frame, c.actuators,
c.cruiseControl.cancel, c.hudControl.visualAlert, c.hudControl.setSpeed, c.hudControl.leftLaneVisible,
c.hudControl.rightLaneVisible, c.hudControl.leftLaneDepart, c.hudControl.rightLaneDepart)
hud_control = c.hudControl
ret = self.CC.update(c.enabled, self.CS, self.frame, c.actuators,
c.cruiseControl.cancel, hud_control.visualAlert, hud_control.setSpeed, hud_control.leftLaneVisible,
hud_control.rightLaneVisible, hud_control.leftLaneDepart, hud_control.rightLaneDepart)
self.frame += 1
return can_sends
return ret

@ -74,7 +74,7 @@ class RadarInterface(RadarInterfaceBase):
self.pts[addr].trackId = self.track_id
self.track_id += 1
valid = msg['STATE'] in [3, 4]
valid = msg['STATE'] in (3, 4)
if valid:
azimuth = math.radians(msg['AZIMUTH'])
self.pts[addr].measured = True

@ -10,13 +10,14 @@ class CarControllerParams:
ACCEL_MAX = 2.0 # m/s
def __init__(self, CP):
if CP.carFingerprint in [CAR.SONATA, CAR.PALISADE, CAR.SANTA_FE, CAR.VELOSTER, CAR.GENESIS_G70, CAR.GENESIS_G70_2020,
CAR.IONIQ_EV_2020, CAR.KIA_CEED, CAR.KIA_SELTOS, CAR.ELANTRA_2021,
CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.SANTA_FE_2022,
CAR.KIA_K5_2021, CAR.KONA_EV, CAR.KONA, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022]:
self.STEER_MAX = 384
else:
# To determine the limit for your car, find the maximum value that the stock LKAS will request.
# If the max stock LKAS request is <384, add your car to this list.
if CP.carFingerprint in (CAR.GENESIS_G80, CAR.GENESIS_G90, CAR.ELANTRA, CAR.HYUNDAI_GENESIS, CAR.ELANTRA_GT_I30, CAR.IONIQ,
CAR.IONIQ_EV_LTD, CAR.IONIQ_PHEV, CAR.SANTA_FE_PHEV_2022, CAR.SONATA_LF, CAR.KIA_FORTE, CAR.KIA_NIRO_HEV,
CAR.KIA_NIRO_HEV_2021, CAR.KIA_OPTIMA_H, CAR.KIA_OPTIMA, CAR.KIA_SORENTO, CAR.KIA_STINGER):
self.STEER_MAX = 255
else:
self.STEER_MAX = 384
self.STEER_DELTA_UP = 3
self.STEER_DELTA_DOWN = 7
self.STEER_DRIVER_ALLOWANCE = 50
@ -41,6 +42,7 @@ class CAR:
SANTA_FE = "HYUNDAI SANTA FE 2019"
SANTA_FE_2022 = "HYUNDAI SANTA FE 2022"
SANTA_FE_HEV_2022 = "HYUNDAI SANTA FE HYBRID 2022"
SANTA_FE_PHEV_2022 = "HYUNDAI SANTA FE PlUG-IN HYBRID 2022"
SONATA = "HYUNDAI SONATA 2020"
SONATA_LF = "HYUNDAI SONATA 2019"
PALISADE = "HYUNDAI PALISADE 2020"
@ -498,6 +500,23 @@ FW_VERSIONS = {
b'\xf1\x87391312MTC1',
],
},
CAR.SANTA_FE_PHEV_2022: {
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x8799110CL500\xf1\x00TMhe SCC FHCUP 1.00 1.00 99110-CL500 ',
],
(Ecu.eps, 0x7d4, None): [
b'\xf1\x00TM MDPS C 1.00 1.02 56310-CLAC0 4TSHC102',
],
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00TMP MFC AT USA LHD 1.00 1.03 99211-S1500 210224',
],
(Ecu.transmission, 0x7e1, None): [
b'\xf1\x8795441-3D121\x00\xf1\x81E16\x00\x00\x00\x00\x00\x00\x00\xf1\x00PSBG2333 E16\x00\x00\x00\x00\x00\x00\x00TTM2P16SA0o\x88^\xbe',
],
(Ecu.engine, 0x7e0, None): [
b'\xf1\x87391312MTF0',
],
},
CAR.KIA_STINGER: {
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00CK__ SCC F_CUP 1.00 1.01 96400-J5100 ',
@ -777,25 +796,22 @@ FW_VERSIONS = {
b'\xf1\x00DEev SCC F-CUP 1.00 1.00 99110-Q4000 ',
b'\xf1\x00DEev SCC F-CUP 1.00 1.02 96400-Q4100 ',
b'\xf1\x00DEev SCC F-CUP 1.00 1.03 96400-Q4100 ',
b'\xf1\x00OSev SCC F-CUP 1.00 1.01 99110-K4000 ',
b'\xf1\x8799110Q4000\xf1\x00DEev SCC F-CUP 1.00 1.00 99110-Q4000 ',
b'\xf1\x8799110Q4100\xf1\x00DEev SCC F-CUP 1.00 1.00 99110-Q4100 ',
b'\xf1\x8799110Q4500\xf1\000DEev SCC F-CUP 1.00 1.00 99110-Q4500 ',
],
(Ecu.esp, 0x7D1, None): [
b'\xf1\x00OS IEB \r 212 \x11\x13 58520-K4000',
b'\xf1\x8799110Q4600\xf1\x00DEev SCC FNCUP 1.00 1.00 99110-Q4600 ',
b'\xf1\x8799110Q4600\xf1\x00DEev SCC FHCUP 1.00 1.00 99110-Q4600 ',
],
(Ecu.eps, 0x7D4, None): [
b'\xf1\x00DE MDPS C 1.00 1.05 56310Q4000\x00 4DEEC105',
b'\xf1\x00DE MDPS C 1.00 1.05 56310Q4100\x00 4DEEC105',
b'\xf1\x00OS MDPS C 1.00 1.04 56310K4050\x00 4OEDC104',
],
(Ecu.fwdCamera, 0x7C4, None): [
b'\xf1\000DEE MFC AT EUR LHD 1.00 1.00 99211-Q4100 200706',
b'\xf1\x00DEE MFC AT EUR LHD 1.00 1.00 99211-Q4000 191211',
b'\xf1\x00DEE MFC AT USA LHD 1.00 1.00 99211-Q4000 191211',
b'\xf1\x00DEE MFC AT USA LHD 1.00 1.03 95740-Q4000 180821',
b'\xf1\x00OSE LKAS AT EUR LHD 1.00 1.00 95740-K4100 W40',
b'\xf1\x00DEE MFC AT USA LHD 1.00 1.01 99211-Q4500 210428',
],
},
CAR.KIA_NIRO_HEV: {
@ -981,25 +997,25 @@ FW_VERSIONS = {
}
CHECKSUM = {
"crc8": [CAR.SANTA_FE, CAR.SONATA, CAR.PALISADE, CAR.KIA_SELTOS, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.SANTA_FE_HEV_2022],
"crc8": [CAR.SANTA_FE, CAR.SONATA, CAR.PALISADE, CAR.KIA_SELTOS, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022],
"6B": [CAR.KIA_SORENTO, CAR.HYUNDAI_GENESIS],
}
FEATURES = {
# which message has the gear
"use_cluster_gears": set([CAR.ELANTRA, CAR.ELANTRA_GT_I30, CAR.KONA]),
"use_tcu_gears": set([CAR.KIA_OPTIMA, CAR.SONATA_LF, CAR.VELOSTER]),
"use_elect_gears": set([CAR.KIA_NIRO_EV, CAR.KIA_NIRO_HEV, 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]),
"use_cluster_gears": {CAR.ELANTRA, CAR.ELANTRA_GT_I30, CAR.KONA},
"use_tcu_gears": {CAR.KIA_OPTIMA, CAR.SONATA_LF, CAR.VELOSTER},
"use_elect_gears": {CAR.KIA_NIRO_EV, CAR.KIA_NIRO_HEV, 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},
# these cars use the FCA11 message for the AEB and FCW signals, all others use SCC12
"use_fca": set([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]),
"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},
}
HYBRID_CAR = set([CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.KIA_NIRO_HEV, CAR.KIA_NIRO_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.IONIQ, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022]) # these cars use a different gas signal
EV_CAR = set([CAR.IONIQ_EV_2020, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.KIA_NIRO_EV])
HYBRID_CAR = {CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.KIA_NIRO_HEV, 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} # these cars use a different gas signal
EV_CAR = {CAR.IONIQ_EV_2020, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.KIA_NIRO_EV}
# these cars require a special panda safety mode due to missing counters and checksums in the messages
LEGACY_SAFETY_MODE_CAR = set([CAR.HYUNDAI_GENESIS, CAR.IONIQ_EV_2020, CAR.IONIQ_EV_LTD, CAR.IONIQ_PHEV, CAR.IONIQ, CAR.KONA_EV, CAR.KIA_SORENTO, CAR.SONATA_LF, CAR.KIA_NIRO_EV, CAR.KIA_OPTIMA, CAR.VELOSTER, CAR.KIA_STINGER, CAR.GENESIS_G70, CAR.GENESIS_G80, CAR.KIA_CEED, CAR.ELANTRA, CAR.IONIQ_HEV_2022])
LEGACY_SAFETY_MODE_CAR = {CAR.HYUNDAI_GENESIS, CAR.IONIQ_EV_2020, CAR.IONIQ_EV_LTD, CAR.IONIQ_PHEV, CAR.IONIQ, CAR.KONA_EV, CAR.KIA_SORENTO, CAR.SONATA_LF, CAR.KIA_OPTIMA, CAR.VELOSTER, CAR.KIA_STINGER, CAR.GENESIS_G70, CAR.GENESIS_G80, CAR.KIA_CEED, CAR.ELANTRA, CAR.IONIQ_HEV_2022}
# If 0x500 is present on bus 1 it probably has a Mando radar outputting radar points.
# If no points are outputted by default it might be possible to turn it on using selfdrive/debug/hyundai_enable_radar_points.py
@ -1020,7 +1036,7 @@ DBC = {
CAR.IONIQ_HEV_2022: dbc_dict('hyundai_kia_generic', None),
CAR.KIA_FORTE: dbc_dict('hyundai_kia_generic', None),
CAR.KIA_K5_2021: dbc_dict('hyundai_kia_generic', None),
CAR.KIA_NIRO_EV: dbc_dict('hyundai_kia_generic', None),
CAR.KIA_NIRO_EV: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar'),
CAR.KIA_NIRO_HEV: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar'),
CAR.KIA_NIRO_HEV_2021: dbc_dict('hyundai_kia_generic', None),
CAR.KIA_OPTIMA: dbc_dict('hyundai_kia_generic', None),
@ -1034,6 +1050,7 @@ DBC = {
CAR.SANTA_FE: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar'),
CAR.SANTA_FE_2022: dbc_dict('hyundai_kia_generic', None),
CAR.SANTA_FE_HEV_2022: dbc_dict('hyundai_kia_generic', None),
CAR.SANTA_FE_PHEV_2022: dbc_dict('hyundai_kia_generic', None),
CAR.SONATA: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar'),
CAR.SONATA_LF: dbc_dict('hyundai_kia_generic', None), # Has 0x5XX messages, but different format
CAR.PALISADE: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar'),

@ -1,6 +1,7 @@
import os
import time
from typing import Dict
from abc import abstractmethod, ABC
from typing import Dict, Tuple, List
from cereal import car
from common.kalman.simple_kalman import KF1D
@ -14,9 +15,7 @@ from selfdrive.controls.lib.vehicle_model import VehicleModel
GearShifter = car.CarState.GearShifter
EventName = car.CarEvent.EventName
# WARNING: this value was determined based on the model's training distribution,
# model predictions above this speed can be unpredictable
MAX_CTRL_SPEED = (V_CRUISE_MAX + 4) * CV.KPH_TO_MS # 135 + 4 = 86 mph
MAX_CTRL_SPEED = (V_CRUISE_MAX + 4) * CV.KPH_TO_MS
ACCEL_MAX = 2.0
ACCEL_MIN = -3.5
@ -24,7 +23,7 @@ ACCEL_MIN = -3.5
# generic car and radar interfaces
class CarInterfaceBase():
class CarInterfaceBase(ABC):
def __init__(self, CP, CarController, CarState):
self.CP = CP
self.VM = VehicleModel(CP)
@ -50,8 +49,9 @@ class CarInterfaceBase():
return ACCEL_MIN, ACCEL_MAX
@staticmethod
@abstractmethod
def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None):
raise NotImplementedError
pass
@staticmethod
def init(CP, logcan, sendcan):
@ -84,13 +84,10 @@ class CarInterfaceBase():
ret.minEnableSpeed = -1. # enable is done by stock ACC, so ignore this
ret.steerRatioRear = 0. # no rear steering, at least on the listed cars aboveA
ret.openpilotLongitudinalControl = False
ret.minSpeedCan = 0.3
ret.startAccel = -0.8
ret.stopAccel = -2.0
ret.startingAccelRate = 3.2 # brake_travel/s while releasing on restart
ret.stoppingDecelRate = 0.8 # brake_travel/s while trying to stop
ret.vEgoStopping = 0.5
ret.vEgoStarting = 0.5
ret.vEgoStarting = 0.5 # needs to be >= vEgoStopping to avoid state transition oscillation
ret.stoppingControl = True
ret.longitudinalTuning.deadzoneBP = [0.]
ret.longitudinalTuning.deadzoneV = [0.]
@ -102,13 +99,13 @@ class CarInterfaceBase():
ret.longitudinalActuatorDelayUpperBound = 0.15
return ret
# returns a car.CarState, pass in car.CarControl
def update(self, c, can_strings):
raise NotImplementedError
@abstractmethod
def update(self, c: car.CarControl, can_strings: List[bytes]) -> car.CarState:
pass
# return sendcan, pass in a car.CarControl
def apply(self, c):
raise NotImplementedError
@abstractmethod
def apply(self, c: car.CarControl) -> Tuple[car.CarControl.Actuators, List[bytes]]:
pass
def create_common_events(self, cs_out, extra_gears=None, gas_resume_speed=-1, pcm_enable=True):
events = Events()
@ -171,7 +168,7 @@ class CarInterfaceBase():
return events
class RadarInterfaceBase():
class RadarInterfaceBase(ABC):
def __init__(self, CP):
self.pts = {}
self.delay = 0
@ -185,7 +182,7 @@ class RadarInterfaceBase():
return ret
class CarStateBase:
class CarStateBase(ABC):
def __init__(self, CP):
self.CP = CP
self.car_fingerprint = CP.carFingerprint

@ -58,4 +58,8 @@ class CarController():
# send steering command
can_sends.append(mazdacan.create_steering_control(self.packer, CS.CP.carFingerprint,
frame, apply_steer, CS.cam_lkas))
return can_sends
new_actuators = c.actuators.copy()
new_actuators.steer = apply_steer / CarControllerParams.STEER_MAX
return new_actuators, can_sends

@ -22,7 +22,7 @@ class CarInterface(CarInterfaceBase):
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.mazda)]
ret.radarOffCan = True
ret.dashcamOnly = candidate not in [CAR.CX9_2021]
ret.dashcamOnly = candidate not in (CAR.CX9_2021,)
ret.steerActuatorDelay = 0.1
ret.steerRateCost = 1.0
@ -36,7 +36,7 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.19], [0.019]]
ret.lateralTuning.pid.kf = 0.00006
elif candidate in [CAR.CX9, CAR.CX9_2021]:
elif candidate in (CAR.CX9, CAR.CX9_2021):
ret.mass = 4217 * CV.LB_TO_KG + STD_CARGO_KG
ret.wheelbase = 3.1
ret.steerRatio = 17.6
@ -95,6 +95,6 @@ class CarInterface(CarInterfaceBase):
return self.CS.out
def apply(self, c):
can_sends = self.CC.update(c, self.CS, self.frame)
ret = self.CC.update(c, self.CS, self.frame)
self.frame += 1
return can_sends
return ret

@ -50,9 +50,11 @@ FW_VERSIONS = {
b'PYFC-188K2-J\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PYFD-188K2-J\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PYNF-188K2-F\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PX2F-188K2-C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PX2G-188K2-D\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PX2H-188K2-B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PX2H-188K2-D\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PX2H-188K2-G\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PX2K-188K2-B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PX38-188K2-B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PX42-188K2-C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
@ -65,6 +67,7 @@ FW_VERSIONS = {
b'K131-67XK2-B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'K131-67XK2-C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'K131-67XK2-E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'K131-67XK2-F\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.esp, 0x760, None): [
b'K123-437K2-E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
@ -78,7 +81,9 @@ FW_VERSIONS = {
b'B61L-67XK2-T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'B61L-67XK2-V\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'GSH7-67XK2-J\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'GSH7-67XK2-M\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'GSH7-67XK2-N\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'GSH7-67XK2-R\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.transmission, 0x7e1, None): [
b'PA66-21PS1-A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
@ -87,10 +92,12 @@ FW_VERSIONS = {
b'PX68-21PS1-B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PYB1-21PS1-B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PYB1-21PS1-C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PYB1-21PS1-G\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PYB2-21PS1-B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PYB2-21PS1-C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PYB2-21PS1-D\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PYB2-21PS1-G\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PYB2-21PS1-H\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PYNC-21PS1-B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'SH9T-21PS1-D\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
@ -145,10 +152,12 @@ FW_VERSIONS = {
b'BHN1-3210X-J-00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'K070-3210X-C-00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'KR11-3210X-K-00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.engine, 0x7e0, None): [
b'P5JD-188K2-B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PY2P-188K2-C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PYJW-188K2-C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PYKC-188K2-D\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PYKE-188K2-B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
@ -163,11 +172,13 @@ FW_VERSIONS = {
(Ecu.fwdCamera, 0x706, None): [
b'B61L-67XK2-D\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'B61L-67XK2-P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'B61L-67XK2-Q\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'B61L-67XK2-T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.transmission, 0x7e1, None): [
b'PY2S-21PS1-C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'P52G-21PS1-F\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PYKA-21PS1-A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PYKE-21PS1-A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PYKE-21PS1-B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
@ -236,7 +247,7 @@ DBC = {
}
# Gen 1 hardware: same CAN messages and same camera
GEN1 = set([CAR.CX5, CAR.CX9, CAR.CX9_2021, CAR.MAZDA3, CAR.MAZDA6])
GEN1 = {CAR.CX5, CAR.CX9, CAR.CX9_2021, CAR.MAZDA3, CAR.MAZDA6}
# Cars with a steering lockout
STEER_LOCKOUT_CAR = set([CAR.CX5, CAR.CX9, CAR.MAZDA3, CAR.MAZDA6])
STEER_LOCKOUT_CAR = {CAR.CX5, CAR.CX9, CAR.MAZDA3, CAR.MAZDA6}

@ -88,4 +88,5 @@ class CarInterface(CarInterfaceBase):
def apply(self, c):
# in mock no carcontrols
return []
actuators = car.CarControl.Actuators.new_message()
return actuators, []

@ -31,7 +31,7 @@ class CarController():
lkas_hud_info_msg = CS.lkas_hud_info_msg
apply_angle = actuators.steeringAngleDeg
steer_hud_alert = 1 if hud_alert in [VisualAlert.steerRequired, VisualAlert.ldw] else 0
steer_hud_alert = 1 if hud_alert in (VisualAlert.steerRequired, VisualAlert.ldw) else 0
if enabled:
# # windup slower
@ -64,14 +64,14 @@ class CarController():
# send acc cancel cmd if drive is disabled but pcm is still on, or if the system can't be activated
cruise_cancel = 1
if self.CP.carFingerprint in [CAR.ROGUE, CAR.XTRAIL, CAR.ALTIMA] and cruise_cancel:
if self.CP.carFingerprint in (CAR.ROGUE, CAR.XTRAIL, CAR.ALTIMA) and cruise_cancel:
can_sends.append(nissancan.create_acc_cancel_cmd(self.packer, self.car_fingerprint, CS.cruise_throttle_msg, frame))
# TODO: Find better way to cancel!
# For some reason spamming the cancel button is unreliable on the Leaf
# We now cancel by making propilot think the seatbelt is unlatched,
# this generates a beep and a warning message every time you disengage
if self.CP.carFingerprint in [CAR.LEAF, CAR.LEAF_IC] and frame % 2 == 0:
if self.CP.carFingerprint in (CAR.LEAF, CAR.LEAF_IC) and frame % 2 == 0:
can_sends.append(nissancan.create_cancel_msg(self.packer, CS.cancel_msg, cruise_cancel))
can_sends.append(nissancan.create_steering_control(
@ -87,4 +87,7 @@ class CarController():
self.packer, lkas_hud_info_msg, steer_hud_alert
))
return can_sends
new_actuators = actuators.copy()
new_actuators.steeringAngleDeg = apply_angle
return new_actuators, can_sends

@ -23,16 +23,16 @@ class CarState(CarStateBase):
def update(self, cp, cp_adas, cp_cam):
ret = car.CarState.new_message()
if self.CP.carFingerprint in [CAR.ROGUE, CAR.XTRAIL, CAR.ALTIMA]:
if self.CP.carFingerprint in (CAR.ROGUE, CAR.XTRAIL, CAR.ALTIMA):
ret.gas = cp.vl["GAS_PEDAL"]["GAS_PEDAL"]
elif self.CP.carFingerprint in [CAR.LEAF, CAR.LEAF_IC]:
elif self.CP.carFingerprint in (CAR.LEAF, CAR.LEAF_IC):
ret.gas = cp.vl["CRUISE_THROTTLE"]["GAS_PEDAL"]
ret.gasPressed = bool(ret.gas > 3)
if self.CP.carFingerprint in [CAR.ROGUE, CAR.XTRAIL, CAR.ALTIMA]:
if self.CP.carFingerprint in (CAR.ROGUE, CAR.XTRAIL, CAR.ALTIMA):
ret.brakePressed = bool(cp.vl["DOORS_LIGHTS"]["USER_BRAKE_PRESSED"])
elif self.CP.carFingerprint in [CAR.LEAF, CAR.LEAF_IC]:
elif self.CP.carFingerprint in (CAR.LEAF, CAR.LEAF_IC):
ret.brakePressed = bool(cp.vl["CRUISE_THROTTLE"]["USER_BRAKE_PRESSED"])
ret.wheelSpeeds = self.get_wheel_speeds(
@ -51,10 +51,10 @@ class CarState(CarStateBase):
else:
ret.cruiseState.enabled = bool(cp_adas.vl["CRUISE_STATE"]["CRUISE_ENABLED"])
if self.CP.carFingerprint in [CAR.ROGUE, CAR.XTRAIL]:
if self.CP.carFingerprint in (CAR.ROGUE, CAR.XTRAIL):
ret.seatbeltUnlatched = cp.vl["HUD"]["SEATBELT_DRIVER_LATCHED"] == 0
ret.cruiseState.available = bool(cp_cam.vl["PRO_PILOT"]["CRUISE_ON"])
elif self.CP.carFingerprint in [CAR.LEAF, CAR.LEAF_IC]:
elif self.CP.carFingerprint in (CAR.LEAF, CAR.LEAF_IC):
if self.CP.carFingerprint == CAR.LEAF:
ret.seatbeltUnlatched = cp.vl["SEATBELT"]["SEATBELT_DRIVER_LATCHED"] == 0
elif self.CP.carFingerprint == CAR.LEAF_IC:
@ -70,7 +70,7 @@ class CarState(CarStateBase):
speed = cp_adas.vl["PROPILOT_HUD"]["SET_SPEED"]
if speed != 255:
if self.CP.carFingerprint in [CAR.LEAF, CAR.LEAF_IC]:
if self.CP.carFingerprint in (CAR.LEAF, CAR.LEAF_IC):
conversion = CV.MPH_TO_MS if cp.vl["HUD_SETTINGS"]["SPEED_MPH"] else CV.KPH_TO_MS
else:
conversion = CV.MPH_TO_MS if cp.vl["HUD"]["SPEED_MPH"] else CV.KPH_TO_MS
@ -108,7 +108,7 @@ class CarState(CarStateBase):
self.cruise_throttle_msg = copy.copy(cp.vl["CRUISE_THROTTLE"])
if self.CP.carFingerprint in [CAR.LEAF, CAR.LEAF_IC]:
if self.CP.carFingerprint in (CAR.LEAF, CAR.LEAF_IC):
self.cancel_msg = copy.copy(cp.vl["CANCEL_MSG"])
if self.CP.carFingerprint != CAR.ALTIMA:
@ -153,7 +153,7 @@ class CarState(CarStateBase):
("LIGHTS", 10),
]
if CP.carFingerprint in [CAR.ROGUE, CAR.XTRAIL, CAR.ALTIMA]:
if CP.carFingerprint in (CAR.ROGUE, CAR.XTRAIL, CAR.ALTIMA):
signals += [
("USER_BRAKE_PRESSED", "DOORS_LIGHTS", 1),
@ -183,7 +183,7 @@ class CarState(CarStateBase):
("HUD", 25),
]
elif CP.carFingerprint in [CAR.LEAF, CAR.LEAF_IC]:
elif CP.carFingerprint in (CAR.LEAF, CAR.LEAF_IC):
signals += [
("USER_BRAKE_PRESSED", "CRUISE_THROTTLE", 1),
("GAS_PEDAL", "CRUISE_THROTTLE", 0),
@ -344,7 +344,7 @@ class CarState(CarStateBase):
signals = []
checks = []
if CP.carFingerprint in [CAR.ROGUE, CAR.XTRAIL]:
if CP.carFingerprint in (CAR.ROGUE, CAR.XTRAIL):
signals += [
("CRUISE_ON", "PRO_PILOT", 0),
]

@ -21,12 +21,12 @@ class CarInterface(CarInterfaceBase):
ret.steerActuatorDelay = 0.1
if candidate in [CAR.ROGUE, CAR.XTRAIL]:
if candidate in (CAR.ROGUE, CAR.XTRAIL):
ret.mass = 1610 + STD_CARGO_KG
ret.wheelbase = 2.705
ret.centerToFront = ret.wheelbase * 0.44
ret.steerRatio = 17
elif candidate in [CAR.LEAF, CAR.LEAF_IC]:
elif candidate in (CAR.LEAF, CAR.LEAF_IC):
ret.mass = 1610 + STD_CARGO_KG
ret.wheelbase = 2.705
ret.centerToFront = ret.wheelbase * 0.44
@ -78,9 +78,10 @@ class CarInterface(CarInterfaceBase):
return self.CS.out
def apply(self, c):
can_sends = self.CC.update(c.enabled, self.CS, self.frame, c.actuators,
c.cruiseControl.cancel, c.hudControl.visualAlert,
c.hudControl.leftLaneVisible, c.hudControl.rightLaneVisible,
c.hudControl.leftLaneDepart, c.hudControl.rightLaneDepart)
hud_control = c.hudControl
ret = self.CC.update(c.enabled, self.CS, self.frame, c.actuators,
c.cruiseControl.cancel, hud_control.visualAlert,
hud_control.leftLaneVisible, hud_control.rightLaneVisible,
hud_control.leftLaneDepart, hud_control.rightLaneDepart)
self.frame += 1
return can_sends
return ret

@ -8,11 +8,11 @@ class CarController():
def __init__(self, dbc_name, CP, VM):
self.apply_steer_last = 0
self.es_distance_cnt = -1
self.es_accel_cnt = -1
self.es_lkas_cnt = -1
self.cruise_button_prev = 0
self.steer_rate_limited = False
self.p = CarControllerParams(CP)
self.packer = CANPacker(DBC[CP.carFingerprint]['pt'])
def update(self, enabled, CS, frame, actuators, pcm_cancel_cmd, visual_alert, left_line, right_line, left_lane_depart, right_lane_depart):
@ -20,23 +20,23 @@ class CarController():
can_sends = []
# *** steering ***
if (frame % CarControllerParams.STEER_STEP) == 0:
if (frame % self.p.STEER_STEP) == 0:
apply_steer = int(round(actuators.steer * CarControllerParams.STEER_MAX))
apply_steer = int(round(actuators.steer * self.p.STEER_MAX))
# limits due to driver torque
new_steer = int(round(apply_steer))
apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, CarControllerParams)
apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.p)
self.steer_rate_limited = new_steer != apply_steer
if not enabled:
apply_steer = 0
if CS.CP.carFingerprint in PREGLOBAL_CARS:
can_sends.append(subarucan.create_preglobal_steering_control(self.packer, apply_steer, frame, CarControllerParams.STEER_STEP))
can_sends.append(subarucan.create_preglobal_steering_control(self.packer, apply_steer, frame, self.p.STEER_STEP))
else:
can_sends.append(subarucan.create_steering_control(self.packer, apply_steer, frame, CarControllerParams.STEER_STEP))
can_sends.append(subarucan.create_steering_control(self.packer, apply_steer, frame, self.p.STEER_STEP))
self.apply_steer_last = apply_steer
@ -44,7 +44,7 @@ class CarController():
# *** alerts and pcm cancel ***
if CS.CP.carFingerprint in PREGLOBAL_CARS:
if self.es_accel_cnt != CS.es_accel_msg["Counter"]:
if self.es_distance_cnt != CS.es_distance_msg["Counter"]:
# 1 = main, 2 = set shallow, 3 = set deep, 4 = resume shallow, 5 = resume deep
# disengage ACC when OP is disengaged
if pcm_cancel_cmd:
@ -60,8 +60,8 @@ class CarController():
cruise_button = 0
self.cruise_button_prev = cruise_button
can_sends.append(subarucan.create_es_throttle_control(self.packer, cruise_button, CS.es_accel_msg))
self.es_accel_cnt = CS.es_accel_msg["Counter"]
can_sends.append(subarucan.create_preglobal_es_distance(self.packer, cruise_button, CS.es_distance_msg))
self.es_distance_cnt = CS.es_distance_msg["Counter"]
else:
if self.es_distance_cnt != CS.es_distance_msg["Counter"]:
@ -72,4 +72,7 @@ class CarController():
can_sends.append(subarucan.create_es_lkas(self.packer, CS.es_lkas_msg, enabled, visual_alert, left_line, right_line, left_lane_depart, right_lane_depart))
self.es_lkas_cnt = CS.es_lkas_msg["Counter"]
return can_sends
new_actuators = actuators.copy()
new_actuators.steer = self.apply_steer_last / self.p.STEER_MAX
return new_actuators, can_sends

@ -65,14 +65,13 @@ class CarState(CarStateBase):
ret.steerError = cp.vl["Steering_Torque"]["Steer_Error_1"] == 1
if self.car_fingerprint in PREGLOBAL_CARS:
self.cruise_button = cp_cam.vl["ES_CruiseThrottle"]["Cruise_Button"]
self.cruise_button = cp_cam.vl["ES_Distance"]["Cruise_Button"]
self.ready = not cp_cam.vl["ES_DashStatus"]["Not_Ready_Startup"]
self.es_accel_msg = copy.copy(cp_cam.vl["ES_CruiseThrottle"])
else:
ret.steerWarning = cp.vl["Steering_Torque"]["Steer_Warning"] == 1
ret.cruiseState.nonAdaptive = cp_cam.vl["ES_DashStatus"]["Conventional_Cruise"] == 1
self.es_distance_msg = copy.copy(cp_cam.vl["ES_Distance"])
self.es_lkas_msg = copy.copy(cp_cam.vl["ES_LKAS_State"])
self.es_distance_msg = copy.copy(cp_cam.vl["ES_Distance"])
return ret
@ -153,7 +152,7 @@ class CarState(CarStateBase):
("CruiseControl", 50),
]
if CP.carFingerprint in [CAR.LEGACY_PREGLOBAL, CAR.OUTBACK_PREGLOBAL, CAR.OUTBACK_PREGLOBAL_2018]:
if CP.carFingerprint in (CAR.LEGACY_PREGLOBAL, CAR.OUTBACK_PREGLOBAL, CAR.OUTBACK_PREGLOBAL_2018):
checks += [
("Dashlights", 10),
("CruiseControl", 50),
@ -168,28 +167,28 @@ class CarState(CarStateBase):
("Cruise_Set_Speed", "ES_DashStatus", 0),
("Not_Ready_Startup", "ES_DashStatus", 0),
("Throttle_Cruise", "ES_CruiseThrottle", 0),
("Signal1", "ES_CruiseThrottle", 0),
("Cruise_Activated", "ES_CruiseThrottle", 0),
("Signal2", "ES_CruiseThrottle", 0),
("Brake_On", "ES_CruiseThrottle", 0),
("Distance_Swap", "ES_CruiseThrottle", 0),
("Standstill", "ES_CruiseThrottle", 0),
("Signal3", "ES_CruiseThrottle", 0),
("Close_Distance", "ES_CruiseThrottle", 0),
("Signal4", "ES_CruiseThrottle", 0),
("Standstill_2", "ES_CruiseThrottle", 0),
("Cruise_Fault", "ES_CruiseThrottle", 0),
("Signal5", "ES_CruiseThrottle", 0),
("Counter", "ES_CruiseThrottle", 0),
("Signal6", "ES_CruiseThrottle", 0),
("Cruise_Button", "ES_CruiseThrottle", 0),
("Signal7", "ES_CruiseThrottle", 0),
("Cruise_Throttle", "ES_Distance", 0),
("Signal1", "ES_Distance", 0),
("Car_Follow", "ES_Distance", 0),
("Signal2", "ES_Distance", 0),
("Brake_On", "ES_Distance", 0),
("Distance_Swap", "ES_Distance", 0),
("Standstill", "ES_Distance", 0),
("Signal3", "ES_Distance", 0),
("Close_Distance", "ES_Distance", 0),
("Signal4", "ES_Distance", 0),
("Standstill_2", "ES_Distance", 0),
("Cruise_Fault", "ES_Distance", 0),
("Signal5", "ES_Distance", 0),
("Counter", "ES_Distance", 0),
("Signal6", "ES_Distance", 0),
("Cruise_Button", "ES_Distance", 0),
("Signal7", "ES_Distance", 0),
]
checks = [
("ES_DashStatus", 20),
("ES_CruiseThrottle", 20),
("ES_Distance", 20),
]
else:
signals = [

@ -45,6 +45,16 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0., 20.], [0., 20.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2, 0.3], [0.02, 0.03]]
if candidate == CAR.IMPREZA_2020:
ret.mass = 1480. + STD_CARGO_KG
ret.wheelbase = 2.67
ret.centerToFront = ret.wheelbase * 0.5
ret.steerRatio = 17 # learned, 14 stock
ret.steerActuatorDelay = 0.1
ret.lateralTuning.pid.kf = 0.00005
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0., 14., 23.], [0., 14., 23.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.045, 0.042, 0.20], [0.04, 0.035, 0.045]]
if candidate == CAR.FORESTER:
ret.mass = 1568. + STD_CARGO_KG
ret.wheelbase = 2.67
@ -55,7 +65,7 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0., 14., 23.], [0., 14., 23.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.01, 0.065, 0.2], [0.001, 0.015, 0.025]]
if candidate in [CAR.FORESTER_PREGLOBAL, CAR.OUTBACK_PREGLOBAL_2018]:
if candidate in (CAR.FORESTER_PREGLOBAL, CAR.OUTBACK_PREGLOBAL_2018):
ret.safetyConfigs[0].safetyParam = 1 # Outback 2018-2019 and Forester have reversed driver torque signal
ret.mass = 1568 + STD_CARGO_KG
ret.wheelbase = 2.67
@ -112,8 +122,9 @@ class CarInterface(CarInterfaceBase):
return self.CS.out
def apply(self, c):
can_sends = self.CC.update(c.enabled, self.CS, self.frame, c.actuators,
c.cruiseControl.cancel, c.hudControl.visualAlert,
c.hudControl.leftLaneVisible, c.hudControl.rightLaneVisible, c.hudControl.leftLaneDepart, c.hudControl.rightLaneDepart)
hud_control = c.hudControl
ret = self.CC.update(c.enabled, self.CS, self.frame, c.actuators,
c.cruiseControl.cancel, hud_control.visualAlert,
hud_control.leftLaneVisible, hud_control.rightLaneVisible, hud_control.leftLaneDepart, hud_control.rightLaneDepart)
self.frame += 1
return can_sends
return ret

@ -80,11 +80,11 @@ def create_preglobal_steering_control(packer, apply_steer, frame, steer_step):
return packer.make_can_msg("ES_LKAS", 0, values)
def create_es_throttle_control(packer, cruise_button, es_accel_msg):
def create_preglobal_es_distance(packer, cruise_button, es_distance_msg):
values = copy.copy(es_accel_msg)
values = copy.copy(es_distance_msg)
values["Cruise_Button"] = cruise_button
values["Checksum"] = subaru_preglobal_checksum(packer, values, "ES_CruiseThrottle")
values["Checksum"] = subaru_preglobal_checksum(packer, values, "ES_Distance")
return packer.make_can_msg("ES_CruiseThrottle", 0, values)
return packer.make_can_msg("ES_Distance", 0, values)

@ -5,17 +5,22 @@ from cereal import car
Ecu = car.CarParams.Ecu
class CarControllerParams:
STEER_MAX = 2047 # max_steer 4095
STEER_STEP = 2 # how often we update the steer cmd
STEER_DELTA_UP = 50 # torque increase per refresh, 0.8s to max
STEER_DELTA_DOWN = 70 # torque decrease per refresh
STEER_DRIVER_ALLOWANCE = 60 # allowed driver torque before start limiting
STEER_DRIVER_MULTIPLIER = 10 # weight driver torque heavily
STEER_DRIVER_FACTOR = 1 # from dbc
def __init__(self, CP):
if CP.carFingerprint == CAR.IMPREZA_2020:
self.STEER_MAX = 1439
else:
self.STEER_MAX = 2047
self.STEER_STEP = 2 # how often we update the steer cmd
self.STEER_DELTA_UP = 50 # torque increase per refresh, 0.8s to max
self.STEER_DELTA_DOWN = 70 # torque decrease per refresh
self.STEER_DRIVER_ALLOWANCE = 60 # allowed driver torque before start limiting
self.STEER_DRIVER_MULTIPLIER = 10 # weight driver torque heavily
self.STEER_DRIVER_FACTOR = 1 # from dbc
class CAR:
ASCENT = "SUBARU ASCENT LIMITED 2019"
IMPREZA = "SUBARU IMPREZA LIMITED 2019"
IMPREZA_2020 = "SUBARU IMPREZA SPORT 2020"
FORESTER = "SUBARU FORESTER 2019"
FORESTER_PREGLOBAL = "SUBARU FORESTER 2017 - 2018"
LEGACY_PREGLOBAL = "SUBARU LEGACY 2015 - 2018"
@ -23,54 +28,340 @@ class CAR:
OUTBACK_PREGLOBAL_2018 = "SUBARU OUTBACK 2018 - 2019"
FINGERPRINTS = {
CAR.ASCENT: [{
# SUBARU ASCENT LIMITED 2019
2: 8, 64: 8, 65: 8, 72: 8, 73: 8, 280: 8, 281: 8, 290: 8, 312: 8, 313: 8, 314: 8, 315: 8, 316: 8, 326: 8, 544: 8, 545: 8, 546: 8, 552: 8, 554: 8, 557: 8, 576: 8, 577: 8, 722: 8, 801: 8, 802: 8, 805: 8, 808: 8, 811: 8, 816: 8, 826: 8, 837: 8, 838: 8, 839: 8, 842: 8, 912: 8, 915: 8, 940: 8, 1614: 8, 1617: 8, 1632: 8, 1650: 8, 1657: 8, 1658: 8, 1677: 8, 1722: 8, 1743: 8, 1759: 8, 1785: 5, 1786: 5, 1787: 5, 1788: 8
}],
CAR.IMPREZA: [{
2: 8, 64: 8, 65: 8, 72: 8, 73: 8, 280: 8, 281: 8, 290: 8, 312: 8, 313: 8, 314: 8, 315: 8, 316: 8, 326: 8, 372: 8, 544: 8, 545: 8, 546: 8, 552: 8, 554: 8, 557: 8, 576: 8, 577: 8, 722: 8, 801: 8, 802: 8, 805: 8, 808: 8, 811: 8, 816: 8, 826: 8, 827: 8, 837: 8, 838: 8, 839: 8, 842: 8, 912: 8, 915: 8, 940: 8, 1614: 8, 1617: 8, 1632: 8, 1650: 8, 1657: 8, 1658: 8, 1677: 8, 1697: 8, 1722: 8, 1743: 8, 1759: 8, 1786: 5, 1787: 5, 1788: 8, 1809: 8, 1813: 8, 1817: 8, 1821: 8, 1840: 8, 1848: 8, 1924: 8, 1932: 8, 1952: 8, 1960: 8
}],
CAR.IMPREZA_2020: [{
2: 8, 64: 8, 65: 8, 72: 8, 73: 8, 280: 8, 281: 8, 282: 8, 290: 8, 312: 8, 313: 8, 314: 8, 315: 8, 316: 8, 326: 8, 372: 8, 544: 8, 545: 8, 546: 8, 552: 8, 554: 8, 557: 8, 576: 8, 577: 8, 722: 8, 801: 8, 802: 8, 803: 8, 805: 8, 808: 8, 816: 8, 826: 8, 837: 8, 838: 8, 839: 8, 842: 8, 912: 8, 915: 8, 940: 8, 1617: 8, 1632: 8, 1650: 8, 1677: 8, 1697: 8, 1722: 8, 1743: 8, 1759: 8, 1786: 5, 1787: 5, 1788: 8, 1809: 8, 1813: 8, 1817: 8, 1821: 8, 1840: 8, 1848: 8, 1924: 8, 1932: 8, 1952: 8, 1960: 8, 1968: 8, 1976: 8, 2015: 8, 2016: 8, 2024: 8
},
{
2: 8, 64: 8, 65: 8, 72: 8, 73: 8, 280: 8, 281: 8, 282: 8, 290: 8, 312: 8, 313: 8, 314: 8, 315: 8, 316: 8, 326: 8, 544: 8, 545: 8, 546: 8, 554: 8, 557: 8, 576: 8, 577: 8, 801: 8, 802: 8, 803: 8, 805: 8, 808: 8, 816: 8, 826: 8, 837: 8, 838: 8, 839: 8, 842: 8, 912: 8, 915: 8, 940: 8, 1614: 8, 1617: 8, 1632: 8, 1657: 8, 1658: 8, 1677: 8, 1697: 8, 1743: 8, 1759: 8, 1786: 5, 1787: 5, 1788: 8, 1809: 8, 1813: 8, 1817: 8, 1821: 8, 1840: 8, 1848: 8, 1924: 8, 1932: 8, 1952: 8, 1960: 8
}],
CAR.FORESTER: [{
# Forester 2019-2020
2: 8, 64: 8, 65: 8, 72: 8, 73: 8, 280: 8, 281: 8, 282: 8, 290: 8, 312: 8, 313: 8, 314: 8, 315: 8, 316: 8, 326: 8, 372: 8, 544: 8, 545: 8, 546: 8, 552: 8, 554: 8, 557: 8, 576: 8, 577: 8, 722: 8, 801: 8, 802: 8, 803: 8, 805: 8, 808: 8, 811: 8, 816: 8, 826: 8, 837: 8, 838: 8, 839: 8, 842: 8, 912: 8, 915: 8, 940: 8, 961: 8, 984: 8, 1614: 8, 1617: 8, 1632: 8, 1650: 8, 1651: 8, 1657: 8, 1658: 8, 1677: 8, 1697: 8, 1698: 8, 1722: 8, 1743: 8, 1759: 8, 1787: 5, 1788: 8, 1809: 8, 1813: 8, 1817: 8, 1821: 8, 1840: 8, 1848: 8, 1924: 8, 1932: 8, 1952: 8, 1960: 8
}],
CAR.OUTBACK_PREGLOBAL: [{
# OUTBACK PREMIUM 2.5i 2015
2: 8, 208: 8, 209: 4, 210: 8, 211: 7, 212: 8, 320: 8, 321: 8, 324: 8, 328: 8, 329: 8, 336: 2, 338: 8, 342: 8, 346: 8, 352: 8, 353: 8, 354: 8, 356: 8, 358: 8, 359: 8, 392: 8, 640: 8, 642: 8, 644: 8, 864: 8, 865: 8, 866: 8, 872: 8, 880: 8, 881: 8, 882: 8, 884: 8, 977: 8, 1632: 8, 1745: 8, 1786: 5, 1882: 8, 2015: 8, 2016: 8, 2024: 8, 604: 8, 885: 8, 1788: 8, 316: 8, 1614: 8, 1640: 8, 1657: 8, 1658: 8, 1672: 8, 1743: 8, 1785: 5, 1787: 5
}
FW_VERSIONS = {
CAR.ASCENT: {
(Ecu.esp, 0x7b0, None): [
b'\xa5 \x19\x02\x00',
b'\xa5 !\002\000',
b'\xf1\x82\xa5 \x19\x02\x00',
],
(Ecu.eps, 0x746, None): [
b'\x85\xc0\xd0\x00',
b'\005\xc0\xd0\000',
b'\x95\xc0\xd0\x00',
],
(Ecu.fwdCamera, 0x787, None): [
b'\x00\x00d\xb9\x1f@ \x10',
b'\000\000e~\037@ \'',
b'\x00\x00e@\x1f@ $',
],
(Ecu.engine, 0x7e0, None): [
b'\xbb,\xa0t\a',
b'\xf1\x82\xbb,\xa0t\x87',
b'\xf1\x82\xbb,\xa0t\a',
b'\xf1\x82\xd9,\xa0@\a',
b'\xf1\x82\xd1,\xa0q\x07',
],
(Ecu.transmission, 0x7e1, None): [
b'\x00\xfe\xf7\x00\x00',
b'\001\xfe\xf9\000\000',
b'\x01\xfe\xf7\x00\x00',
],
},
# OUTBACK PREMIUM 3.6i 2015
{
2: 8, 208: 8, 209: 4, 210: 8, 211: 7, 212: 8, 320: 8, 321: 8, 324: 8, 328: 8, 329: 8, 336: 2, 338: 8, 342: 8, 392: 8, 604: 8, 640: 8, 642: 8, 644: 8, 864: 8, 865: 8, 866: 8, 872: 8, 880: 8, 881: 8, 882: 8, 884: 8, 977: 8, 1632: 8, 1745: 8, 1779: 8, 1786: 5
CAR.IMPREZA: {
(Ecu.esp, 0x7b0, None): [
b'\x7a\x94\x3f\x90\x00',
b'\xa2 \x185\x00',
b'\xa2 \x193\x00',
b'z\x94.\x90\x00',
b'z\x94\b\x90\x01',
b'\xa2 \x19`\x00',
b'z\x94\f\x90\001',
b'z\x9c\x19\x80\x01',
b'z\x94\x08\x90\x00',
],
(Ecu.eps, 0x746, None): [
b'\x7a\xc0\x0c\x00',
b'z\xc0\b\x00',
b'\x8a\xc0\x00\x00',
b'z\xc0\x04\x00',
b'z\xc0\x00\x00',
b'\x8a\xc0\x10\x00',
],
(Ecu.fwdCamera, 0x787, None): [
b'\x00\x00\x64\xb5\x1f\x40\x20\x0e',
b'\x00\x00d\xdc\x1f@ \x0e',
b'\x00\x00e\x1c\x1f@ \x14',
b'\x00\x00d)\x1f@ \a',
b'\x00\x00e+\x1f@ \x14',
b'\000\000e+\000\000\000\000',
b'\000\000dd\037@ \016',
b'\000\000e\002\037@ \024',
b'\x00\x00d)\x00\x00\x00\x00',
b'\x00\x00c\xf4\x00\x00\x00\x00',
],
(Ecu.engine, 0x7e0, None): [
b'\xaa\x61\x66\x73\x07',
b'\xbeacr\a',
b'\xc5!`r\a',
b'\xaa!ds\a',
b'\xaa!`u\a',
b'\xaa!dq\a',
b'\xaa!dt\a',
b'\xf1\x00\xa2\x10\t'
b'\xc5!dr\a',
b'\xc5!ar\a',
b'\xbe!as\a',
b'\xc5!ds\a',
b'\xc5!`s\a',
b'\xaa!au\a',
b'\xbe!at\a',
b'\xaa\x00Bu\x07',
b'\xc5!dr\x07',
b'\xaa!aw\x07',
],
(Ecu.transmission, 0x7e1, None): [
b'\xe3\xe5\x46\x31\x00',
b'\xe4\xe5\x061\x00',
b'\xe5\xf5\x04\x00\x00',
b'\xe3\xf5G\x00\x00',
b'\xe3\xf5\a\x00\x00',
b'\xe3\xf5C\x00\x00',
b'\xf1\x00\xa4\x10@'
b'\xe5\xf5B\x00\x00',
b'\xe5\xf5$\000\000',
b'\xe4\xf5\a\000\000',
b'\xe3\xf5F\000\000',
b'\xe4\xf5\002\000\000',
b'\xe3\xd0\x081\x00',
b'\xe3\xf5\x06\x00\x00',
],
},
# OUTBACK LIMITED 2.5i 2018
{
2: 8, 208: 8, 209: 4, 210: 8, 211: 7, 212: 8, 316: 8, 320: 8, 321: 8, 324: 8, 328: 8, 329: 8, 336: 2, 338: 8, 342: 8, 352: 8, 353: 8, 354: 8, 356: 8, 358: 8, 359: 8, 392: 8, 554: 8, 604: 8, 640: 8, 642: 8, 644: 8, 805: 8, 864: 8, 865: 8, 866: 8, 872: 8, 880: 8, 881: 8, 882: 8, 884: 8, 885: 8, 977: 8, 1614: 8, 1632: 8, 1657: 8, 1658: 8, 1672: 8, 1722: 8, 1736: 8, 1743: 8, 1745: 8, 1785: 5, 1786: 5, 1787: 5, 1788: 8
}],
CAR.OUTBACK_PREGLOBAL_2018: [{
# OUTBACK LIMITED 3.6R 2019
2: 8, 208: 8, 209: 4, 210: 8, 211: 7, 212: 8, 316: 8, 320: 8, 321: 8, 324: 8, 328: 8, 329: 8, 336: 2, 338: 8, 342: 8, 352: 8, 353: 8, 354: 8, 356: 8, 358: 8, 359: 8, 392: 8, 554: 8, 604: 8, 640: 8, 642: 8, 644: 8, 805: 8, 864: 8, 865: 8, 866: 8, 872: 8, 880: 8, 881: 8, 882: 8, 884: 8, 885: 8, 886: 2, 977: 8, 1614: 8, 1632: 8, 1657: 8, 1658: 8, 1672: 8, 1736: 8, 1743: 8, 1745: 8, 1785: 5, 1786: 5, 1787: 5, 1788: 8, 1862: 8, 1870: 8, 1920: 8, 1927: 8, 1928: 8, 1935: 8, 1968: 8, 1976: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8
}],
CAR.FORESTER_PREGLOBAL: [{
# FORESTER PREMIUM 2.5i 2017
2: 8, 112: 8, 117: 8, 128: 8, 208: 8, 209: 4, 210: 8, 211: 7, 212: 8, 320: 8, 321: 8, 324: 8, 328: 8, 329: 8, 336: 2, 338: 8, 340: 7, 342: 8, 352: 8, 353: 8, 354: 8, 355: 8, 356: 8, 554: 8, 604: 8, 640: 8, 641: 8, 642: 8, 805: 8, 864: 8, 865: 8, 866: 8, 872: 8, 880: 8, 881: 8, 882: 8, 884: 8, 885: 8, 886: 1, 888: 8, 977: 8, 1398: 8, 1632: 8, 1743: 8, 1744: 8, 1745: 8, 1785: 5, 1786: 5, 1787: 5, 1788: 8, 1882: 8, 1895: 8, 1903: 8, 1986: 8, 1994: 8, 2015: 8, 2016: 8, 2024: 8, 644:8, 890:8, 1736:8
}],
CAR.LEGACY_PREGLOBAL: [{
# LEGACY 2.5i 2017
2: 8, 208: 8, 209: 4, 210: 8, 211: 7, 212: 8, 320: 8, 321: 8, 324: 8, 328: 8, 329: 8, 336: 2, 338: 8, 342: 8, 392: 8, 604: 8, 640: 8, 642: 8, 864: 8, 865: 8, 866: 8, 872: 8, 880: 8, 881: 8, 882: 8, 884: 8, 885: 8, 977: 8, 1632: 8, 1640: 8, 1736: 8, 1745: 8, 1785: 5, 1786: 5, 1787: 5, 1788: 8, 352: 8, 353: 8, 354: 8, 356: 8, 358: 8, 359: 8, 644: 8
CAR.IMPREZA_2020: {
(Ecu.esp, 0x7b0, None): [
b'\xa2 \0314\000',
b'\xa2 \0313\000',
b'\xa2 !i\000',
b'\xa2 !`\000',
],
(Ecu.eps, 0x746, None): [
b'\x9a\xc0\000\000',
b'\n\xc0\004\000',
],
(Ecu.fwdCamera, 0x787, None): [
b'\000\000eb\037@ \"',
b'\000\000e\x8f\037@ )',
],
(Ecu.engine, 0x7e0, None): [
b'\xca!ap\a',
b'\xca!`p\a',
b'\xca!`0\a',
b'\xcc\"f0\a',
b'\xcc!fp\a',
],
(Ecu.transmission, 0x7e1, None): [
b'\xe6\xf5\004\000\000',
b'\xe6\xf5$\000\000',
b'\xe7\xf6B0\000',
b'\xe7\xf5D0\000',
],
},
# LEGACY 2018
{
2: 8, 208: 8, 209: 4, 210: 8, 211: 7, 212: 8, 316: 8, 320: 8, 321: 8, 324: 8, 328: 8, 329: 8, 336: 2, 338: 8, 342: 8, 392: 8, 604: 8, 640: 8, 642: 8, 864: 8, 865: 8, 866: 8, 872: 8, 880: 8, 881: 8, 882: 8, 884: 8, 885: 8, 977: 8, 1614: 8, 1632: 8, 1640: 8, 1657: 8, 1658: 8, 1672: 8, 1722: 8, 1743: 8, 1745: 8, 1778: 8, 1785: 5, 1786: 5, 1787: 5, 1788: 8, 2015: 8, 2016: 8, 2024: 8
CAR.FORESTER: {
(Ecu.esp, 0x7b0, None): [
b'\xa3 \030\024\000',
b'\xa3 \024\000',
b'\xa3 \031\024\000',
b'\xa3 \024\001',
],
(Ecu.eps, 0x746, None): [
b'\x8d\xc0\004\000',
],
(Ecu.fwdCamera, 0x787, None): [
b'\000\000e!\037@ \021',
b'\000\000e\x97\037@ 0',
b'\000\000e`\037@ ',
b'\xf1\x00\xac\x02\x00',
],
(Ecu.engine, 0x7e0, None): [
b'\xb6\"`A\a',
b'\xcf"`0\a',
b'\xcb\"`@\a',
b'\xcb\"`p\a',
b'\xf1\x00\xa2\x10\n',
],
(Ecu.transmission, 0x7e1, None): [
b'\032\xf6B0\000',
b'\032\xf6F`\000',
b'\032\xf6b`\000',
b'\032\xf6B`\000'
b'\xf1\x00\xa4\x10@',
],
},
CAR.FORESTER_PREGLOBAL: {
(Ecu.esp, 0x7b0, None): [
b'\x7d\x97\x14\x40',
b'\xf1\x00\xbb\x0c\x04',
],
(Ecu.eps, 0x746, None): [
b'}\xc0\x10\x00',
b'm\xc0\x10\x00',
],
(Ecu.fwdCamera, 0x787, None): [
b'\x00\x00\x64\x35\x1f\x40\x20\x09',
b'\x00\x00c\xe9\x1f@ \x03',
b'\x00\x00d\xd3\x1f@ \t'
],
(Ecu.engine, 0x7e0, None): [
b'\xba"@p\a',
b'\xa7)\xa0q\a',
b'\xf1\x82\xa7)\xa0q\a',
b'\xba"@@\a',
],
(Ecu.transmission, 0x7e1, None): [
b'\xdc\xf2\x60\x60\x00',
b'\xdc\xf2@`\x00',
b'\xda\xfd\xe0\x80\x00',
b'\xdc\xf2`\x81\000',
b'\xdc\xf2`\x80\x00',
],
},
CAR.LEGACY_PREGLOBAL: {
(Ecu.esp, 0x7b0, None): [
b'k\x97D\x00',
b'[\xba\xc4\x03',
b'{\x97D\x00',
b'[\x97D\000',
],
(Ecu.eps, 0x746, None): [
b'[\xb0\x00\x01',
b'K\xb0\x00\x01',
b'k\xb0\x00\x00',
],
(Ecu.fwdCamera, 0x787, None): [
b'\x00\x00c\xb7\x1f@\x10\x16',
b'\x00\x00c\x94\x1f@\x10\x08',
b'\x00\x00c\xec\x1f@ \x04',
],
(Ecu.engine, 0x7e0, None): [
b'\xab*@r\a',
b'\xa0+@p\x07',
b'\xb4"@0\x07',
b'\xa0"@q\a',
],
(Ecu.transmission, 0x7e1, None): [
b'\xbe\xf2\x00p\x00',
b'\xbf\xfb\xc0\x80\x00',
b'\xbd\xf2\x00`\x00',
b'\xbf\xf2\000\x80\000',
],
},
CAR.OUTBACK_PREGLOBAL: {
(Ecu.esp, 0x7b0, None): [
b'{\x9a\xac\x00',
b'k\x97\xac\x00',
b'\x5b\xf7\xbc\x03',
b'[\xf7\xac\x03',
b'{\x97\xac\x00',
b'k\x9a\xac\000',
b'[\xba\xac\x03',
b'[\xf7\xac\000',
],
(Ecu.eps, 0x746, None): [
b'k\xb0\x00\x00',
b'[\xb0\x00\x00',
b'\x4b\xb0\x00\x02',
b'K\xb0\x00\x00',
b'{\xb0\x00\x01',
],
(Ecu.fwdCamera, 0x787, None): [
b'\x00\x00c\xec\x1f@ \x04',
b'\x00\x00c\xd1\x1f@\x10\x17',
b'\xf1\x00\xf0\xe0\x0e',
b'\x00\x00c\x94\x00\x00\x00\x00',
b'\x00\x00c\x94\x1f@\x10\b',
b'\x00\x00c\xb7\x1f@\x10\x16',
b'\000\000c\x90\037@\020\016',
b'\x00\x00c\xec\x37@\x04',
],
(Ecu.engine, 0x7e0, None): [
b'\xb4+@p\a',
b'\xab\"@@\a',
b'\xa0\x62\x41\x71\x07',
b'\xa0*@q\a',
b'\xab*@@\a',
b'\xb4"@0\a',
b'\xb4"@p\a',
b'\xab"@s\a',
b'\xab+@@\a',
b'\xb4"@r\a',
b'\xa0+@@\x07'
b'\xa0\"@\x80\a',
],
(Ecu.transmission, 0x7e1, None): [
b'\xbd\xfb\xe0\x80\x00',
b'\xbe\xf2@\x80\x00',
b'\xbf\xe2\x40\x80\x00',
b'\xbf\xf2@\x80\x00',
b'\xbe\xf2@p\x00',
b'\xbd\xf2@`\x00',
b'\xbd\xf2@\x81\000',
b'\xbe\xfb\xe0p\000',
b'\xbf\xfb\xe0b\x00',
],
},
CAR.OUTBACK_PREGLOBAL_2018: {
(Ecu.esp, 0x7b0, None): [
b'\x8b\x97\xac\x00',
b'\x8b\x9a\xac\x00',
b'\x9b\x97\xac\x00',
b'\x8b\x97\xbc\x00',
b'\x8b\x99\xac\x00',
b'\x9b\x9a\xac\000',
b'\x9b\x97\xbe\x10',
],
(Ecu.eps, 0x746, None): [
b'{\xb0\x00\x00',
b'{\xb0\x00\x01',
],
(Ecu.fwdCamera, 0x787, None): [
b'\x00\x00df\x1f@ \n',
b'\x00\x00d\xfe\x1f@ \x15',
b'\x00\x00d\x95\x00\x00\x00\x00',
b'\x00\x00d\x95\x1f@ \x0f',
b'\x00\x00d\xfe\x00\x00\x00\x00',
b'\x00\x00e\x19\x1f@ \x15',
],
(Ecu.engine, 0x7e0, None): [
b'\xb5"@p\a',
b'\xb5+@@\a',
b'\xb5"@P\a',
b'\xc4"@0\a',
b'\xb5b@1\x07',
b'\xb5q\xe0@\a',
b'\xc4+@0\a',
b'\xc4b@p\a',
],
(Ecu.transmission, 0x7e1, None): [
b'\xbc\xf2@\x81\x00',
b'\xbc\xfb\xe0\x80\x00',
b'\xbc\xf2@\x80\x00',
b'\xbb\xf2@`\x00',
b'\xbc\xe2@\x80\x00',
b'\xbc\xfb\xe0`\x00',
b'\xbc\xaf\xe0`\x00',
b'\xbb\xfb\xe0`\000',
],
},
# LEGACY 2018
{
2: 8, 208: 8, 209: 4, 210: 8, 211: 7, 212: 8, 316: 8, 320: 8, 321: 8, 324: 8, 328: 8, 329: 8, 336: 2, 338: 8, 342: 8, 352: 8, 353: 8, 354: 8, 356: 8, 358: 8, 359: 8, 392: 8, 554: 8, 604: 8, 640: 8, 642: 8, 805: 8, 864: 8, 865: 8, 866: 8, 872: 8, 880: 8, 881: 8, 882: 8, 884: 8, 885: 8, 977: 8, 1614: 8, 1632: 8, 1640: 8, 1657: 8, 1658: 8, 1672: 8, 1722: 8, 1743: 8, 1745: 8, 1785: 5, 1786: 5, 1787: 5, 1788: 8, 2015: 8, 2016: 8, 2024: 8
}],
}
STEER_THRESHOLD = {
CAR.ASCENT: 80,
CAR.IMPREZA: 80,
CAR.IMPREZA_2020: 80,
CAR.FORESTER: 80,
CAR.FORESTER_PREGLOBAL: 75,
CAR.LEGACY_PREGLOBAL: 75,
@ -81,6 +372,7 @@ STEER_THRESHOLD = {
DBC = {
CAR.ASCENT: dbc_dict('subaru_global_2017_generated', None),
CAR.IMPREZA: dbc_dict('subaru_global_2017_generated', None),
CAR.IMPREZA_2020: dbc_dict('subaru_global_2017_generated', None),
CAR.FORESTER: dbc_dict('subaru_global_2017_generated', None),
CAR.FORESTER_PREGLOBAL: dbc_dict('subaru_forester_2017_generated', None),
CAR.LEGACY_PREGLOBAL: dbc_dict('subaru_outback_2015_generated', None),

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

Loading…
Cancel
Save