openpilot v0.6.5 release

pull/417/head
Vehicle Researcher 2019-10-09 18:43:53 +00:00
parent 3a04a69cbe
commit cf80f7a28b
242 changed files with 3841 additions and 2511 deletions

View File

@ -0,0 +1,25 @@
---
name: Bug report
about: Create a report to help us improve openpilot
title: ''
labels: 'bug'
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**How to reproduce or log data**
Steps to reproduce the behavior, or a explorer/cabana link to the exact drive and timestamp of when the bug occurred.
**Expected behavior**
A clear and concise description of what you expected to happen.
** Device/Version information (please complete the following information):**
- Device: [e.g. EON/EON Gold]
- Version: [e.g. 0.6.4], or commit hash when on devel
- Car make/model [e.g. Toyota Prius 2016]
**Additional context**
Add any other context about the problem here.

View File

@ -0,0 +1,21 @@
Choose one of the templates below:
# Fingerprint
This pull requests adds a fingerprint for <Make - Model - Year - Trim>.
This is an explorer link to a drive with the stock system enabled: ...
# Car support
This pull requests adds support for <Make - Model - Year - Trim>.
This is an explorer link to a drive with the stock system enabled: ...
This is an explorer link to a drive with openpilot system enabled: ...
# Feature
This pull requests adds feature X
## Description
Explain what the feature does
## Testing
Explain how the feature was tested. Either by the added unit tests, or what tests were performed while driving.

3
.gitignore vendored
View File

@ -4,6 +4,7 @@ venv/
.ipynb_checkpoints
.idea
.sconsign.dblite
.vscode
model2.png
a.out
@ -30,7 +31,7 @@ selfdrive/logcatd/logcatd
selfdrive/mapd/default_speeds_by_region.json
selfdrive/proclogd/proclogd
selfdrive/ui/ui
selfdrive/test/tests/plant/out
selfdrive/test/longitudinal_maneuvers/out
selfdrive/visiond/visiond
selfdrive/loggerd/loggerd
selfdrive/sensord/gpsd

View File

@ -6,43 +6,66 @@ RUN apt-get update && apt-get install -y \
build-essential \
bzip2 \
clang \
cmake \
curl \
ffmpeg \
git \
libarchive-dev \
libavcodec-dev \
libavdevice-dev \
libavfilter-dev \
libavresample-dev \
libavutil-dev \
libbz2-dev \
libcurl4-openssl-dev \
libeigen3-dev \
libffi-dev \
libglew-dev \
libglib2.0-0 \
liblzma-dev \
libmysqlclient-dev \
libomp-dev \
libopencv-dev \
libssl-dev \
libswscale-dev \
libtool \
libusb-1.0-0 \
libzmq5-dev \
locales \
ocl-icd-libopencl1 \
ocl-icd-opencl-dev \
opencl-headers \
pkg-config \
python-dev \
python-pip \
screen \
sudo \
vim \
wget
COPY phonelibs/install_capnp.sh /tmp/install_capnp.sh
RUN /tmp/install_capnp.sh
RUN pip install --upgrade pip==18.0
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}"
RUN pyenv install 3.7.3
RUN pyenv global 3.7.3
RUN pyenv rehash
RUN pip install pipenv==2018.11.26
COPY Pipfile /tmp/
COPY Pipfile.lock /tmp/
RUN cd /tmp && pipenv install --deploy --system
ENV PYTHONPATH /tmp/openpilot:$PYTHONPATH
RUN python --version
RUN cd /tmp && pipenv install --system --deploy
RUN git clone --branch v0.6.2 https://github.com/commaai/openpilot-tools.git /tmp/openpilot/tools
RUN pip install -r /tmp/openpilot/tools/requirements.txt
RUN pip install fastcluster==1.1.20 scipy==0.19.1 dictdiffer==0.8.0 azure-batch==4.1.3 azure-common==1.1.16 azure-nspkg==3.0.0 azure-storage-blob==1.3.1 azure-storage-common==1.3.0 azure-storage-nspkg==3.0.0
# Install subset of dev dependencies needed for CI
RUN pip install matplotlib==3.1.1 dictdiffer==0.8.0 fastcluster==1.1.25 aenum==2.2.1 scipy==1.3.1 lru-dict==1.1.6 tenacity==5.1.1 azure-common==1.1.23 azure-nspkg==3.0.2 azure-storage-blob==2.1.0 azure-storage-common==2.1.0 azure-storage-nspkg==3.1.0 pycurl==7.43.0.3
COPY phonelibs/install_capnp.sh /tmp/install_capnp.sh
RUN /tmp/install_capnp.sh
RUN git clone --branch v0.6.5 https://github.com/commaai/openpilot-tools.git /tmp/openpilot/tools
ENV PYTHONPATH /tmp/openpilot:${PYTHONPATH}
COPY ./.pylintrc /tmp/openpilot/.pylintrc
COPY ./common /tmp/openpilot/common
COPY ./cereal /tmp/openpilot/cereal

59
Pipfile
View File

@ -4,16 +4,16 @@ url = "https://pypi.org/simple"
verify_ssl = true
[dev-packages]
ipython = "<6.0"
aenum = "*"
azure-batch = "==4.1.3"
azure-common = "==1.1.16"
azure-nspkg = "==3.0.1"
azure-storage-blob = "==1.3.1"
azure-storage-common = "==1.3.0"
azure-storage-nspkg = "==3.0.0"
opencv-python= "==3.4.2.17"
PyQt5 = "*"
ipython = "*"
azure-common = "*"
azure-nspkg = "*"
azure-storage-blob = "*"
azure-storage-common = "*"
azure-storage-nspkg = "*"
bincopy = "*"
bleach = "==1.5.0"
bleach = "*"
boto = "*"
"boto3" = "*"
celery = "*"
@ -23,7 +23,6 @@ decorator = "*"
dlib = "*"
dominate = "*"
elasticsearch = "*"
entium = "==0.1.4"
fasteners = "*"
future = "*"
futures = "*"
@ -32,32 +31,31 @@ pycocotools = {git = "https://github.com/cocodataset/cocoapi.git",subdirectory =
gunicorn = "*"
"h5py" = "*"
hexdump = "*"
"html5lib" = "==0.9999999"
"html5lib" = "*"
imageio = "*"
intervaltree = "*"
ipykernel = "<5.0"
ipykernel = "*"
joblib = "*"
json-logging-py = "*"
jupyter = "*"
libarchive = "*"
lru-dict = "*"
lxml = "*"
matplotlib = "==2.2.3"
"mpld3" = "*"
msgpack-python = "*"
nbstripout = "*"
nose-parameterized = "*"
numpy = "==1.14.5"
osmium = "==2.15.0"
pbr = "==5.1.3"
numpy = "*"
osmium = "*"
pbr = "*"
percache = "*"
pprofile = "*"
psutil = "*"
pycurl = "*"
git-pylint-commit-hook = "==2.5.1"
git-pylint-commit-hook = "*"
pymongo = "*"
"pynmea2" = "*"
pypolyline = "==0.1.17"
pypolyline = "*"
pysendfile = "*"
python-logstash = "*"
pyvcd = "*"
@ -68,11 +66,9 @@ scikit-image = "*"
"subprocess32" = "*"
supervisor = "*"
tenacity = "*"
tensorflow-gpu = "==1.13.0rc0"
"transforms3d" = "*"
tensorflow-gpu = ""
utm = "*"
"v4l2" = "*"
visdom = "*"
PyJWT = "==1.4.1"
PyMySQL = "==0.9.2"
Theano = "*"
@ -81,26 +77,28 @@ Werkzeug = "*"
Flask-Cors = "*"
Flask-SocketIO = "*"
"GeoAlchemy2" = "*"
Keras = ">=2.1.6"
keras-maskrcnn = "*"
keras-retinanet = "*"
Pygments = "*"
PyNaCl = "*"
"PySDL2" = "*"
reverse_geocoder = "*"
Shapely = "*"
SQLAlchemy = "==1.2.7"
SQLAlchemy = "*"
uWSGI = "*"
scipy = "*"
fastcluster = "==1.1.25"
fastcluster = "*"
backports-abc = "*"
pygame = "*"
simplejson = "*"
python-logstash-async = "*"
pandas = "*"
seaborn = "*"
tensorflow-estimator = "==1.10.12"
tensorflow-estimator = "*"
pyproj = "*"
mock = "*"
blinker = "*"
gast = "==0.2.2"
matplotlib = "*"
dictdiffer = "*"
aenum = "*"
[packages]
overpy = {git = "https://github.com/commaai/python-overpy.git",ref = "f86529af402d4642e1faeb146671c40284007323"}
@ -126,7 +124,7 @@ tqdm = "*"
Cython = "*"
PyYAML = "*"
websocket_client = "*"
Logentries = {git = "https://github.com/commaai/le_python.git",ref = "5eef8f5be5929d33973e1b10e686fa0cdcd6792f"}
Logentries = {git = "https://github.com/commaai/le_python.git",ref = "feaeacb48f7f4bdb02c0a8fc092326d4e101b7f2"}
urllib3 = "*"
chardet = "*"
idna = "*"
@ -140,6 +138,7 @@ nose = "*"
pyflakes = "*"
pylint = "*"
pycryptodome = "*"
pillow = "*"
[requires]
python_version = "2.7"
python_version = "3.7.3"

2033
Pipfile.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@
Welcome to openpilot
======
[openpilot](http://github.com/commaai/openpilot) is an open source driving agent. Currently, it performs the functions of Adaptive Cruise Control (ACC) and Lane Keeping Assist System (LKAS) for selected Honda, Toyota, Acura, Lexus, Chevrolet, Hyundai, Kia. It's about on par with Tesla Autopilot and GM Super Cruise, and better than [all other manufacturers](http://www.thedrive.com/tech/5707/the-war-for-autonomous-driving-part-iii-us-vs-germany-vs-japan).
[openpilot](http://github.com/commaai/openpilot) is an open source driver assistance system. Currently, it performs the functions of Adaptive Cruise Control (ACC) and Lane Keeping Assist System (LKAS) for selected Honda, Toyota, Acura, Lexus, Chevrolet, Hyundai, Kia. It's about on par with Tesla Autopilot and GM Super Cruise, and better than [all other manufacturers](http://www.thedrive.com/tech/5707/the-war-for-autonomous-driving-part-iii-us-vs-germany-vs-japan).
The openpilot codebase has been written to be concise and to enable rapid prototyping. We look forward to your contributions - improving real vehicle automation has never been easier.
@ -93,6 +93,7 @@ Supported Cars
| Kia | Optima 2019 | SCC + LKAS | Yes | Stock | 0mph | 0mph | Custom<sup>6</sup>|
| Kia | Sorento 2018 | All | Yes | Stock | 0mph | 0mph | Custom<sup>6</sup>|
| Kia | Stinger 2018 | SCC + LKAS | Yes | Stock | 0mph | 0mph | Custom<sup>6</sup>|
| Lexus | CT Hybrid 2017-18 | All | Yes | Yes<sup>2</sup>| 0mph | 0mph | Toyota |
| Lexus | ES Hybrid 2019 | All | Yes | Yes | 0mph | 0mph | Toyota |
| Lexus | RX Hybrid 2016-19 | All | Yes | Yes<sup>2</sup>| 0mph | 0mph | Toyota |
| Lexus | IS 2017-2019 | All | Yes | Stock | 22mph | 0mph | Toyota |
@ -144,7 +145,7 @@ In Progress Cars
------
- All TSS-P Toyota with Steering Assist and LSS-P Lexus with Steering Assist or Lane Keep Assist.
- All Hyundai with SmartSense.
- All Kia with SCC and LKAS.
- All Kia, Genesis with SCC and LKAS.
- All Chrysler, Jeep, Fiat with Adaptive Cruise Control and LaneSense.
- All Subaru with EyeSight.

View File

@ -1,3 +1,17 @@
Version 0.6.5 (2019-10-07)
========================
* NEOS update: upgrade to Python3 and new installer!
* comma Harness support!
* New driving model: lateral control has lower reliance on lanelines
* New driver monitoring model: more accurate face and eye detection
* Redesign offroad screen to display updates and alerts
* Increase maximum allowed acceleration
* Prevent car 12V battery drain by cutting off EON charge after 3 days of no drive
* Lexus CT Hybrid support thanks to thomaspich!
* Louder chime for critical alerts
* Add toggle to switch to dashcam mode
* Fix "invalid vehicle params" error on DSU-less Toyota
Version 0.6.4 (2019-09-08)
========================
* Forward stock AEB for Honda Nidec

Binary file not shown.

Binary file not shown.

View File

@ -4,7 +4,7 @@ from datetime import datetime, timedelta
from selfdrive.version import version
class Api(object):
class Api():
def __init__(self, dongle_id):
self.dongle_id = dongle_id
with open('/persist/comma/id_rsa') as f:
@ -27,7 +27,7 @@ class Api(object):
'iat': now,
'exp': now + timedelta(hours=1)
}
return jwt.encode(payload, self.private_key, algorithm='RS256')
return jwt.encode(payload, self.private_key, algorithm='RS256').decode('utf8')
def api_get(endpoint, method='GET', timeout=None, access_token=None, **params):
backend = "https://api.commadotai.com/"

View File

@ -0,0 +1,23 @@
import os
import sysconfig
from Cython.Distutils import build_ext
def get_ext_filename_without_platform_suffix(filename):
name, ext = os.path.splitext(filename)
ext_suffix = sysconfig.get_config_var('EXT_SUFFIX')
if ext_suffix == ext:
return filename
ext_suffix = ext_suffix.replace(ext, '')
idx = name.find(ext_suffix)
if idx == -1:
return filename
else:
return name[:idx] + ext
class BuildExtWithoutPlatformSuffix(build_ext):
def get_ext_filename(self, ext_name):
filename = super().get_ext_filename(ext_name)
return get_ext_filename_without_platform_suffix(filename)

View File

@ -17,10 +17,10 @@ DBCSignal = namedtuple(
"factor", "offset", "tmin", "tmax", "units"])
class dbc(object):
class dbc():
def __init__(self, fn):
self.name, _ = os.path.splitext(os.path.basename(fn))
with open(fn) as f:
with open(fn, encoding="ascii") as f:
self.txt = f.readlines()
self._warned_addresses = set()
@ -41,7 +41,7 @@ class dbc(object):
self.def_vals = defaultdict(list)
# lookup to bit reverse each byte
self.bits_index = [(i & ~0b111) + ((-i-1) & 0b111) for i in xrange(64)]
self.bits_index = [(i & ~0b111) + ((-i-1) & 0b111) for i in range(64)]
for l in self.txt:
l = l.strip()
@ -213,7 +213,7 @@ class dbc(object):
if debug:
print(name)
st = x[2].ljust(8, '\x00')
st = x[2].ljust(8, b'\x00')
le, be = None, None
for s in msg[1]:

View File

@ -9,7 +9,7 @@ def ffi_wrap(name, c_code, c_header, tmpdir="/tmp/ccache", cflags="", libraries=
if libraries is None:
libraries = []
cache = name + "_" + hashlib.sha1(c_code).hexdigest()
cache = name + "_" + hashlib.sha1(c_code.encode('utf-8')).hexdigest()
try:
os.mkdir(tmpdir)
except OSError:

View File

@ -32,7 +32,7 @@ def get_tmpdir_on_same_filesystem(path):
return "/{}/runner/tmp".format(parts[1])
return "/tmp"
class AutoMoveTempdir(object):
class AutoMoveTempdir():
def __init__(self, target_path, temp_dir=None):
self._target_path = target_path
self._path = tempfile.mkdtemp(dir=temp_dir)
@ -52,7 +52,7 @@ class AutoMoveTempdir(object):
else:
shutil.rmtree(self._path)
class NamedTemporaryDir(object):
class NamedTemporaryDir():
def __init__(self, temp_dir=None):
self._path = tempfile.mkdtemp(dir=temp_dir)

View File

@ -1,7 +1,7 @@
all: simple_kalman_impl.so
simple_kalman_impl.so: simple_kalman_impl.pyx simple_kalman_impl.pxd simple_kalman_setup.py
python2 simple_kalman_setup.py build_ext --inplace
python3 simple_kalman_setup.py build_ext --inplace
rm -rf build
rm simple_kalman_impl.c

View File

@ -5,6 +5,6 @@ import subprocess
kalman_dir = os.path.dirname(os.path.abspath(__file__))
subprocess.check_call(["make", "simple_kalman_impl.so"], cwd=kalman_dir)
from simple_kalman_impl import KF1D as KF1D
from .simple_kalman_impl import KF1D as KF1D
# Silence pyflakes
assert KF1D

View File

@ -1,3 +1,4 @@
# cython: language_level=3
cdef class KF1D:
def __init__(self, x0, A, C, K):
@ -32,4 +33,4 @@ cdef class KF1D:
@x.setter
def x(self, x):
self.x0_0 = x[0][0]
self.x1_0 = x[1][0]
self.x1_0 = x[1][0]

View File

@ -1,5 +1,9 @@
from distutils.core import setup, Extension
from distutils.core import Extension, setup # pylint: disable=import-error,no-name-in-module
from Cython.Build import cythonize
from common.cython_hacks import BuildExtWithoutPlatformSuffix
setup(name='Simple Kalman Implementation',
ext_modules=cythonize(Extension("simple_kalman_impl", ["simple_kalman_impl.pyx"])))
cmdclass={'build_ext': BuildExtWithoutPlatformSuffix},
ext_modules=cythonize(Extension("simple_kalman_impl", ["simple_kalman_impl.pyx"])))

View File

@ -12,7 +12,10 @@ def interp(x, xp, fp):
hi += 1
low = hi - 1
return fp[-1] if hi == N and xv > xp[low] else (
fp[0] if hi == 0 else
fp[0] if hi == 0 else
(xv - xp[low]) * (fp[hi] - fp[low]) / (xp[hi] - xp[low]) + fp[low])
return [get_interp(v) for v in x] if hasattr(
x, '__iter__') else get_interp(x)
def mean(x):
return sum(x) / len(x)

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
"""ROS has a parameter server, we have files.
The parameter store is a persistent key value store, implemented as a directory with a writer lock.
@ -59,29 +59,38 @@ keys = {
"ControlsParams": [TxType.PERSISTENT],
"DoUninstall": [TxType.CLEAR_ON_MANAGER_START],
"DongleId": [TxType.PERSISTENT],
"GithubSshKeys": [TxType.PERSISTENT],
"GitBranch": [TxType.PERSISTENT],
"GitCommit": [TxType.PERSISTENT],
"GitRemote": [TxType.PERSISTENT],
"GithubSshKeys": [TxType.PERSISTENT],
"HasAcceptedTerms": [TxType.PERSISTENT],
"HasCompletedSetup": [TxType.PERSISTENT],
"IsGeofenceEnabled": [TxType.PERSISTENT],
"IsMetric": [TxType.PERSISTENT],
"IsRHD": [TxType.PERSISTENT],
"IsUpdateAvailable": [TxType.PERSISTENT],
"IsUploadRawEnabled": [TxType.PERSISTENT],
"IsUploadVideoOverCellularEnabled": [TxType.PERSISTENT],
"LastUpdateTime": [TxType.PERSISTENT],
"LimitSetSpeed": [TxType.PERSISTENT],
"LimitSetSpeedNeural": [TxType.PERSISTENT],
"LiveParameters": [TxType.PERSISTENT],
"LongitudinalControl": [TxType.PERSISTENT],
"OpenpilotEnabledToggle": [TxType.PERSISTENT],
"Passive": [TxType.PERSISTENT],
"RecordFront": [TxType.PERSISTENT],
"ReleaseNotes": [TxType.PERSISTENT],
"ShouldDoUpdate": [TxType.CLEAR_ON_MANAGER_START],
"SpeedLimitOffset": [TxType.PERSISTENT],
"SubscriberInfo": [TxType.PERSISTENT],
"TermsVersion": [TxType.PERSISTENT],
"TrainingVersion": [TxType.PERSISTENT],
"UpdateAvailable": [TxType.CLEAR_ON_MANAGER_START],
"Version": [TxType.PERSISTENT],
"Offroad_ChargeDisabled": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT],
"Offroad_TemperatureTooHigh": [TxType.CLEAR_ON_MANAGER_START],
"Offroad_ConnectivityNeededPrompt": [TxType.CLEAR_ON_MANAGER_START],
"Offroad_ConnectivityNeeded": [TxType.CLEAR_ON_MANAGER_START],
}
@ -93,7 +102,7 @@ def fsync_dir(path):
os.close(fd)
class FileLock(object):
class FileLock():
def __init__(self, path, create):
self._path = path
self._create = create
@ -109,7 +118,7 @@ class FileLock(object):
self._fd = None
class DBAccessor(object):
class DBAccessor():
def __init__(self, path):
self._path = path
self._vals = None
@ -279,6 +288,9 @@ def read_db(params_path, key):
return None
def write_db(params_path, key, value):
if isinstance(value, str):
value = value.encode('utf8')
prev_umask = os.umask(0)
lock = FileLock(params_path+"/.lock", True)
lock.acquire()
@ -297,7 +309,7 @@ def write_db(params_path, key, value):
os.umask(prev_umask)
lock.release()
class Params(object):
class Params():
def __init__(self, db='/data/params'):
self.db = db
@ -328,7 +340,7 @@ class Params(object):
with self.transaction(write=True) as txn:
txn.delete(key)
def get(self, key, block=False):
def get(self, key, block=False, encoding=None):
if key not in keys:
raise UnknownKeyName(key)
@ -338,9 +350,21 @@ class Params(object):
break
# is polling really the best we can do?
time.sleep(0.05)
if ret is not None and encoding is not None:
ret = ret.decode(encoding)
return ret
def put(self, key, dat):
"""
Warning: This function blocks until the param is written to disk!
In very rare cases this can take over a second, and your code will hang.
Use the put_nonblocking helper function in time sensitive code, but
in general try to avoid writing params as much as possible.
"""
if key not in keys:
raise UnknownKeyName(key)

View File

@ -1,6 +1,6 @@
import time
class Profiler(object):
class Profiler():
def __init__(self, enabled=False):
self.enabled = enabled
self.cp = {}

View File

@ -19,6 +19,7 @@ assert sec_since_boot
DT_CTRL = 0.01 # controlsd
DT_PLAN = 0.05 # mpc
DT_MDL = 0.05 # model
DT_RDR = 0.05 # radar
DT_DMON = 0.1 # driver monitoring
DT_TRML = 0.5 # thermald and manager
@ -43,7 +44,7 @@ def set_realtime_priority(level):
return subprocess.call(['chrt', '-f', '-p', str(level), str(tid)])
class Ratekeeper(object):
class Ratekeeper():
def __init__(self, rate, print_delay_threshold=0.):
"""Rate in Hz for ratekeeping. print_delay_threshold must be nonnegative."""
self._interval = 1. / rate

28
common/spinner.py 100644
View File

@ -0,0 +1,28 @@
import os
import subprocess
from common.basedir import BASEDIR
class Spinner():
def __enter__(self):
self.spinner_proc = subprocess.Popen(["./spinner"],
stdin=subprocess.PIPE,
cwd=os.path.join(BASEDIR, "selfdrive", "ui", "spinner"),
close_fds=True)
return self
def update(self, spinner_text):
self.spinner_proc.stdin.write(spinner_text.encode('utf8') + b"\n")
self.spinner_proc.stdin.flush()
def __exit__(self, type, value, traceback):
self.spinner_proc.stdin.close()
self.spinner_proc.terminate()
if __name__ == "__main__":
import time
with Spinner() as s:
s.update("Spinner text")
time.sleep(5.0)

View File

@ -11,7 +11,7 @@ class RunningStat():
self.n = priors[2]
self.M_last = self.M
self.S_last = self.S
else:
self.reset()
@ -70,4 +70,4 @@ class RunningStatFilter():
pass
# self.filtered_stat.push_data(self.filtered_stat.mean())
# class SequentialBayesian():
# class SequentialBayesian():

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
import sympy as sp
import numpy as np

View File

@ -125,7 +125,7 @@ def img_from_device(pt_device):
#TODO please use generic img transform below
def rotate_img(img, eulers, crop=None, intrinsics=eon_intrinsics):
import cv2
import cv2 # pylint: disable=no-name-in-module, import-error
size = img.shape[:2]
rot = orient.rot_from_euler(eulers)
@ -138,8 +138,8 @@ def rotate_img(img, eulers, crop=None, intrinsics=eon_intrinsics):
warped_quadrangle = np.column_stack((warped_quadrangle_full[:,0]/warped_quadrangle_full[:,2],
warped_quadrangle_full[:,1]/warped_quadrangle_full[:,2])).astype(np.float32)
if crop:
W_border = (size[1] - crop[0])/2
H_border = (size[0] - crop[1])/2
W_border = (size[1] - crop[0])//2
H_border = (size[0] - crop[1])//2
outside_crop = (((warped_quadrangle[:,0] < W_border) |
(warped_quadrangle[:,0] >= size[1] - W_border)) &
((warped_quadrangle[:,1] < H_border) |
@ -183,7 +183,8 @@ def transform_img(base_img,
alpha=1.0,
beta=0,
blur=0):
import cv2
import cv2 # pylint: disable=no-name-in-module, import-error
cv2.setNumThreads(1)
if yuv:
base_img = cv2.cvtColor(base_img, cv2.COLOR_YUV2RGB_I420)
@ -240,7 +241,7 @@ def transform_img(base_img,
def yuv_crop(frame, output_size, center=None):
# output_size in camera coordinates so u,v
# center in array coordinates so row, column
import cv2
import cv2 # pylint: disable=no-name-in-module, import-error
rgb = cv2.cvtColor(frame, cv2.COLOR_YUV2RGB_I420)
if not center:
center = (rgb.shape[0]/2, rgb.shape[1]/2)

View File

@ -65,7 +65,7 @@ def ecef2geodetic(ecef, radians=False):
geodetic = np.column_stack((lat, lon, h))
return geodetic.reshape(input_shape)
class LocalCoord(object):
class LocalCoord():
"""
Allows conversions to local frames. In this case NED.
That is: North East Down from the start position in

View File

@ -29,7 +29,7 @@ def euler2quat(eulers):
np.sin(gamma / 2) * np.sin(theta / 2) * np.cos(psi / 2)
quats = array([q0, q1, q2, q3]).T
for i in xrange(len(quats)):
for i in range(len(quats)):
if quats[i,0] < 0:
quats[i] = -quats[i]
return quats.reshape(output_shape)
@ -99,7 +99,7 @@ def rot2quat(rots):
K3[:, 3, 2] = K3[:, 2, 3]
K3[:, 3, 3] = (rots[:, 0, 0] + rots[:, 1, 1] + rots[:, 2, 2]) / 3.0
q = np.empty((len(rots), 4))
for i in xrange(len(rots)):
for i in range(len(rots)):
_, eigvecs = linalg.eigh(K3[i].T)
eigvecs = eigvecs[:,3:]
q[i, 0] = eigvecs[-1]

View File

@ -1,7 +1,7 @@
{
"ota_url": "https://commadist.azureedge.net/neosupdate/ota-signed-4db25072191d24e204a816d73ac9e8c727822a26ed3baf01ecae18167fa2eb11.zip",
"ota_hash": "4db25072191d24e204a816d73ac9e8c727822a26ed3baf01ecae18167fa2eb11",
"recovery_url": "https://commadist.azureedge.net/neosupdate/recovery-31ef14206d3102edf18fb7417ef32ba2d9f37dd2f4443e234c374a70d1bf4662.img",
"recovery_len": 15136044,
"recovery_hash": "31ef14206d3102edf18fb7417ef32ba2d9f37dd2f4443e234c374a70d1bf4662"
"ota_url": "https://commadist.azureedge.net/neosupdate/ota-signed-7a0117425bc4a6673958d265312994e124654a566228f3cec2f0f9bc8120a9ab.zip",
"ota_hash": "7a0117425bc4a6673958d265312994e124654a566228f3cec2f0f9bc8120a9ab",
"recovery_url": "https://commadist.azureedge.net/neosupdate/recovery-3dc234d868c29a3739f6ca3bd47b1c2d3c570d9f478b6849a4fada129ee4af76.img",
"recovery_len": 15848748,
"recovery_hash": "3dc234d868c29a3739f6ca3bd47b1c2d3c570d9f478b6849a4fada129ee4af76"
}

View File

@ -32,6 +32,24 @@ function launch {
echo 0-3 > /dev/cpuset/foreground/cpus
echo 0-3 > /dev/cpuset/android/cpus
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
# Remove old NEOS update file
if [ -d /data/neoupdate ]; then
rm -rf /data/neoupdate
fi
# Check for NEOS update
if [ $(< /VERSION) != "12" ]; then
if [ -f "$DIR/scripts/continue.sh" ]; then
cp "$DIR/scripts/continue.sh" "/data/data/com.termux/files/continue.sh"
fi
git clean -xdf
"$DIR/installer/updater/updater" "file://$DIR/installer/updater/update.json"
fi
# handle pythonpath
ln -s /data/openpilot /data/pythonpath
export PYTHONPATH="$PWD"

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -11,6 +11,6 @@ docker run --rm tmppilot /bin/sh -c 'cd /tmp/openpilot/ && make -C cereal && pyt
docker run --rm tmppilot /bin/sh -c 'cd /tmp/openpilot/ && make -C cereal && python -m unittest discover selfdrive/boardd'
docker run --rm tmppilot /bin/sh -c 'cd /tmp/openpilot/ && make -C cereal && python -m unittest discover selfdrive/controls'
docker run --rm tmppilot /bin/sh -c 'cd /tmp/openpilot/ && python -m unittest discover selfdrive/loggerd'
docker run --rm -v "$(pwd)"/selfdrive/test/tests/plant/out:/tmp/openpilot/selfdrive/test/tests/plant/out tmppilot /bin/sh -c 'cd /tmp/openpilot/selfdrive/test/tests/plant && OPTEST=1 ./test_longitudinal.py'
docker run --rm tmppilot /bin/sh -c 'cd /tmp/openpilot/ && make -C cereal && cd /tmp/openpilot/selfdrive/test/tests/process_replay/ && ./test_processes.py'
docker run --rm -v "$(pwd)"/selfdrive/test/longitudinal_maneuvers/out:/tmp/openpilot/selfdrive/test/longitudinal_maneuvers/out tmppilot /bin/sh -c 'cd /tmp/openpilot/selfdrive/test/longitudinal_maneuvers && OPTEST=1 ./test_longitudinal.py'
docker run --rm tmppilot /bin/sh -c 'cd /tmp/openpilot/ && make -C cereal && cd /tmp/openpilot/selfdrive/test/process_replay/ && ./test_processes.py'
docker run --rm tmppilot /bin/sh -c 'mkdir -p /data/params && cd /tmp/openpilot/ && make -C cereal && cd /tmp/openpilot/selfdrive/test/ && ./test_car_models.py'

Binary file not shown.

View File

@ -1,6 +1,7 @@
#!/usr/bin/env python2.7
#!/usr/bin/env python3.7
import json
import os
import io
import random
import re
import select
@ -10,6 +11,7 @@ import time
import threading
import traceback
import zmq
import base64
import requests
import six.moves.queue
from functools import partial
@ -24,6 +26,7 @@ from common.params import Params
from selfdrive.services import service_list
from selfdrive.swaglog import cloudlog
from selfdrive.version import version, dirty
from functools import reduce
ATHENA_HOST = os.getenv('ATHENA_HOST', 'wss://athena.comma.ai')
HANDLER_THREADS = os.getenv('HANDLER_THREADS', 4)
@ -41,10 +44,11 @@ def handle_long_poll(ws):
threading.Thread(target=ws_send, args=(ws, end_event))
] + [
threading.Thread(target=jsonrpc_handler, args=(end_event,))
for x in xrange(HANDLER_THREADS)
for x in range(HANDLER_THREADS)
]
map(lambda thread: thread.start(), threads)
for thread in threads:
thread.start()
try:
while not end_event.is_set():
time.sleep(0.1)
@ -101,7 +105,7 @@ def startLocalProxy(global_end_event, remote_ws_uri, local_port):
raise Exception("Requested local port not whitelisted")
params = Params()
dongle_id = params.get("DongleId")
dongle_id = params.get("DongleId").decode('utf8')
identity_token = Api(dongle_id).get_token()
ws = create_connection(remote_ws_uri,
cookie="jwt=" + identity_token,
@ -117,8 +121,8 @@ def startLocalProxy(global_end_event, remote_ws_uri, local_port):
threading.Thread(target=ws_proxy_recv, args=(ws, local_sock, ssock, proxy_end_event, global_end_event)),
threading.Thread(target=ws_proxy_send, args=(ws, local_sock, csock, proxy_end_event))
]
map(lambda thread: thread.start(), threads)
for thread in threads:
thread.start()
return {"success": 1}
except Exception as e:
@ -135,16 +139,15 @@ def getPublicKey():
@dispatcher.add_method
def getSshAuthorizedKeys():
with open('/system/comma/home/.ssh/authorized_keys', 'r') as f:
return f.read()
return Params().get("GithubSshKeys", encoding='utf8') or ''
@dispatcher.add_method
def getSimInfo():
sim_state = subprocess.check_output(['getprop', 'gsm.sim.state']).strip().split(',')
network_type = subprocess.check_output(['getprop', 'gsm.network.type']).strip().split(',')
mcc_mnc = subprocess.check_output(['getprop', 'gsm.sim.operator.numeric']).strip() or None
sim_state = subprocess.check_output(['getprop', 'gsm.sim.state'], encoding='utf8').strip().split(',') # pylint: disable=unexpected-keyword-arg
network_type = subprocess.check_output(['getprop', 'gsm.network.type'], encoding='utf8').strip().split(',') # pylint: disable=unexpected-keyword-arg
mcc_mnc = subprocess.check_output(['getprop', 'gsm.sim.operator.numeric'], encoding='utf8').strip() or None # pylint: disable=unexpected-keyword-arg
sim_id_aidl_out = subprocess.check_output(['service', 'call', 'iphonesubinfo', '11'])
sim_id_aidl_out = subprocess.check_output(['service', 'call', 'iphonesubinfo', '11'], encoding='utf8') # pylint: disable=unexpected-keyword-arg
sim_id_aidl_lines = sim_id_aidl_out.split('\n')
if len(sim_id_aidl_lines) > 3:
sim_id_lines = sim_id_aidl_lines[1:4]
@ -160,6 +163,20 @@ def getSimInfo():
'sim_state': sim_state
}
@dispatcher.add_method
def takeSnapshot():
from selfdrive.visiond.snapshot.snapshot import snapshot, jpeg_write
ret = snapshot()
if ret is not None:
def b64jpeg(x):
f = io.BytesIO()
jpeg_write(f, x)
return base64.b64encode(f.getvalue()).decode("utf-8")
return {'jpegBack': b64jpeg(ret[0]),
'jpegFront': b64jpeg(ret[1])}
else:
raise Exception("not available while visiond is started")
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:
@ -221,7 +238,7 @@ def backoff(retries):
def main(gctx=None):
params = Params()
dongle_id = params.get("DongleId")
dongle_id = params.get("DongleId").decode('utf-8')
ws_uri = ATHENA_HOST + "/ws/v2/" + dongle_id
crash.bind_user(id=dongle_id)

View File

@ -78,7 +78,7 @@ boardd.o: boardd.cc
boardd_api_impl.so: libcan_list_to_can_capnp.a boardd_api_impl.pyx boardd_setup.py
python2 boardd_setup.py build_ext --inplace
python3 boardd_setup.py build_ext --inplace
rm -rf build
rm -f boardd_api_impl.cpp

View File

@ -32,26 +32,9 @@
#define RECV_SIZE (0x1000)
#define TIMEOUT 0
#define SAFETY_NOOUTPUT 0
#define SAFETY_HONDA 1
#define SAFETY_TOYOTA 2
#define SAFETY_GM 3
#define SAFETY_HONDA_BOSCH 4
#define SAFETY_FORD 5
#define SAFETY_CADILLAC 6
#define SAFETY_HYUNDAI 7
#define SAFETY_TESLA 8
#define SAFETY_CHRYSLER 9
#define SAFETY_SUBARU 10
#define SAFETY_GM_PASSIVE 11
#define SAFETY_TOYOTA_IPAS 0x1335
#define SAFETY_TOYOTA_NOLIMITS 0x1336
#define SAFETY_ALLOUTPUT 0x1337
#define SAFETY_ELM327 0xE327 // diagnostic only
namespace {
volatile int do_exit = 0;
volatile sig_atomic_t do_exit = 0;
libusb_context *ctx = NULL;
libusb_device_handle *dev_handle;
@ -62,6 +45,10 @@ bool fake_send = false;
bool loopback_can = false;
cereal::HealthData::HwType hw_type = cereal::HealthData::HwType::UNKNOWN;
bool is_pigeon = false;
const uint32_t NO_IGNITION_CNT_MAX = 2 * 60 * 60 * 24 * 3; // turn off charge after 3 days
uint32_t no_ignition_cnt = 0;
bool connected_once = false;
uint8_t ignition_last = 0;
pthread_t safety_setter_thread_handle = -1;
pthread_t pigeon_thread_handle = -1;
@ -89,8 +76,8 @@ void *safety_setter_thread(void *s) {
pthread_mutex_lock(&usb_lock);
// VIN qury done, stop listening to OBDII
libusb_control_transfer(dev_handle, 0x40, 0xdc, SAFETY_NOOUTPUT, 0, NULL, 0, TIMEOUT);
// VIN query done, stop listening to OBDII
libusb_control_transfer(dev_handle, 0x40, 0xdc, (uint16_t)(cereal::CarParams::SafetyModel::NO_OUTPUT), 0, NULL, 0, TIMEOUT);
pthread_mutex_unlock(&usb_lock);
@ -119,48 +106,6 @@ void *safety_setter_thread(void *s) {
auto safety_param = car_params.getSafetyParam();
LOGW("setting safety model: %d with param %d", safety_model, safety_param);
int safety_setting = 0;
switch (safety_model) {
case cereal::CarParams::SafetyModel::NO_OUTPUT:
safety_setting = SAFETY_NOOUTPUT;
break;
case cereal::CarParams::SafetyModel::HONDA:
safety_setting = SAFETY_HONDA;
break;
case cereal::CarParams::SafetyModel::TOYOTA:
safety_setting = SAFETY_TOYOTA;
break;
case cereal::CarParams::SafetyModel::ELM327:
safety_setting = SAFETY_ELM327;
break;
case cereal::CarParams::SafetyModel::GM:
safety_setting = SAFETY_GM;
break;
case cereal::CarParams::SafetyModel::GM_PASSIVE:
safety_setting = SAFETY_GM_PASSIVE;
break;
case cereal::CarParams::SafetyModel::HONDA_BOSCH:
safety_setting = SAFETY_HONDA_BOSCH;
break;
case cereal::CarParams::SafetyModel::FORD:
safety_setting = SAFETY_FORD;
break;
case cereal::CarParams::SafetyModel::CADILLAC:
safety_setting = SAFETY_CADILLAC;
break;
case cereal::CarParams::SafetyModel::HYUNDAI:
safety_setting = SAFETY_HYUNDAI;
break;
case cereal::CarParams::SafetyModel::CHRYSLER:
safety_setting = SAFETY_CHRYSLER;
break;
case cereal::CarParams::SafetyModel::SUBARU:
safety_setting = SAFETY_SUBARU;
break;
default:
LOGE("unknown safety model: %d", safety_model);
}
pthread_mutex_lock(&usb_lock);
// set in the mutex to avoid race
@ -169,7 +114,7 @@ void *safety_setter_thread(void *s) {
// set if long_control is allowed by openpilot. Hardcoded to True for now
libusb_control_transfer(dev_handle, 0x40, 0xdf, 1, 0, NULL, 0, TIMEOUT);
libusb_control_transfer(dev_handle, 0x40, 0xdc, safety_setting, safety_param, NULL, 0, TIMEOUT);
libusb_control_transfer(dev_handle, 0x40, 0xdc, (uint16_t)(cereal::CarParams::SafetyModel(safety_model)), safety_param, NULL, 0, TIMEOUT);
pthread_mutex_unlock(&usb_lock);
@ -180,6 +125,7 @@ void *safety_setter_thread(void *s) {
bool usb_connect() {
int err;
unsigned char hw_query[1] = {0};
ignition_last = 0;
dev_handle = libusb_open_device_with_vid_pid(ctx, 0xbbaa, 0xddcc);
if (dev_handle == NULL) { goto fail; }
@ -197,25 +143,20 @@ bool usb_connect() {
// power off ESP
libusb_control_transfer(dev_handle, 0xc0, 0xd9, 0, 0, NULL, 0, TIMEOUT);
// power on charging (may trigger a reconnection, should be okay)
#ifndef __x86_64__
libusb_control_transfer(dev_handle, 0xc0, 0xe6, 1, 0, NULL, 0, TIMEOUT);
#else
LOGW("not enabling charging on x86_64");
#endif
// diagnostic only is the default, needed for VIN query
libusb_control_transfer(dev_handle, 0x40, 0xdc, SAFETY_ELM327, 0, NULL, 0, TIMEOUT);
if (safety_setter_thread_handle == -1) {
err = pthread_create(&safety_setter_thread_handle, NULL, safety_setter_thread, NULL);
assert(err == 0);
// power on charging, only the first time. Panda can also change mode and it causes a brief disconneciton
#ifndef __x86_64__
if (!connected_once) {
libusb_control_transfer(dev_handle, 0xc0, 0xe6, (uint16_t)(cereal::HealthData::UsbPowerMode::CDP), 0, NULL, 0, TIMEOUT);
}
#endif
connected_once = true;
libusb_control_transfer(dev_handle, 0xc0, 0xc1, 0, 0, hw_query, 1, TIMEOUT);
hw_type = (cereal::HealthData::HwType)(hw_query[0]);
is_pigeon = (hw_type == cereal::HealthData::HwType::GREY_PANDA) || (hw_type == cereal::HealthData::HwType::BLACK_PANDA);
is_pigeon = (hw_type == cereal::HealthData::HwType::GREY_PANDA) ||
(hw_type == cereal::HealthData::HwType::BLACK_PANDA) ||
(hw_type == cereal::HealthData::HwType::UNO);
if (is_pigeon) {
LOGW("panda with gps detected");
pigeon_needs_init = true;
@ -304,8 +245,9 @@ void can_recv(void *s) {
void can_health(void *s) {
int cnt;
int err;
// copied from board/main.c
// copied from panda/board/main.c
struct __attribute__((packed)) health {
uint32_t voltage;
uint32_t current;
@ -315,7 +257,8 @@ void can_health(void *s) {
uint8_t started;
uint8_t controls_allowed;
uint8_t gas_interceptor_detected;
uint8_t car_harness_status_pkt;
uint8_t car_harness_status;
uint8_t usb_power_mode;
} health;
// recv from board
@ -330,6 +273,42 @@ void can_health(void *s) {
pthread_mutex_unlock(&usb_lock);
if (health.started == 0) {
no_ignition_cnt += 1;
} else {
no_ignition_cnt = 0;
}
#ifndef __x86_64__
if ((no_ignition_cnt > NO_IGNITION_CNT_MAX) && (health.usb_power_mode == (uint8_t)(cereal::HealthData::UsbPowerMode::CDP))) {
printf("TURN OFF CHARGING!\n");
pthread_mutex_lock(&usb_lock);
libusb_control_transfer(dev_handle, 0xc0, 0xe6, (uint16_t)(cereal::HealthData::UsbPowerMode::CLIENT), 0, NULL, 0, TIMEOUT);
pthread_mutex_unlock(&usb_lock);
}
#endif
// clear VIN, CarParams, and set new safety on car start
if ((health.started != 0) && (ignition_last == 0)) {
int result = delete_db_value(NULL, "CarVin");
assert((result == 0) || (result == ERR_NO_VALUE));
result = delete_db_value(NULL, "CarParams");
assert((result == 0) || (result == ERR_NO_VALUE));
// diagnostic only is the default, needed for VIN query
pthread_mutex_lock(&usb_lock);
libusb_control_transfer(dev_handle, 0x40, 0xdc, (uint16_t)(cereal::CarParams::SafetyModel::ELM327), 0, NULL, 0, TIMEOUT);
pthread_mutex_unlock(&usb_lock);
if (safety_setter_thread_handle == -1) {
err = pthread_create(&safety_setter_thread_handle, NULL, safety_setter_thread, NULL);
assert(err == 0);
}
}
ignition_last = health.started;
// create message
capnp::MallocMessageBuilder msg;
cereal::Event::Builder event = msg.initRoot<cereal::Event>();
@ -351,6 +330,7 @@ void can_health(void *s) {
healthData.setCanFwdErrs(health.can_fwd_errs);
healthData.setGmlanSendErrs(health.gmlan_send_errs);
healthData.setHwType(hw_type);
healthData.setUsbPowerMode(cereal::HealthData::UsbPowerMode(health.usb_power_mode));
// send to health
auto words = capnp::messageToFlatArray(msg);
@ -481,7 +461,6 @@ void *can_recv_thread(void *crap) {
void *can_health_thread(void *crap) {
LOGD("start health thread");
// health = 8011
void *context = zmq_ctx_new();
void *publisher = zmq_socket(context, ZMQ_PUB);
@ -628,7 +607,7 @@ void *pigeon_thread(void *crap) {
}
if (alen > 0) {
if (dat[0] == (char)0x00){
LOGW("received invalid ublox message, resetting pigeon");
LOGW("received invalid ublox message, resetting panda GPS");
pigeon_init();
} else {
pigeon_publish_raw(publisher, dat, alen);

View File

@ -1,4 +1,5 @@
# distutils: language = c++
# cython: language_level=3
from libcpp.vector cimport vector
from libcpp.string cimport string
from libcpp cimport bool

View File

@ -1,25 +1,29 @@
import subprocess
from distutils.core import setup, Extension
from distutils.core import Extension, setup # pylint: disable=import-error,no-name-in-module
from Cython.Build import cythonize
from common.cython_hacks import BuildExtWithoutPlatformSuffix
PHONELIBS = '../../phonelibs'
ARCH = subprocess.check_output(["uname", "-m"]).rstrip()
ARCH = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip() # pylint: disable=unexpected-keyword-arg
ARCH_DIR = 'x64' if ARCH == "x86_64" else 'aarch64'
setup(name='Boardd API Implementation',
ext_modules=cythonize(
Extension(
"boardd_api_impl",
libraries=[':libcan_list_to_can_capnp.a', ':libcapnp.a', ':libcapnp.a', ':libkj.a'],
library_dirs=[
'./',
PHONELIBS + '/capnp-cpp/' + ARCH_DIR + '/lib/',
PHONELIBS + '/capnp-c/' + ARCH_DIR + '/lib/'
],
sources=['boardd_api_impl.pyx'],
language="c++",
extra_compile_args=["-std=c++11"],
)
)
cmdclass={'build_ext': BuildExtWithoutPlatformSuffix},
ext_modules=cythonize(
Extension(
"boardd_api_impl",
libraries=[':libcan_list_to_can_capnp.a', ':libcapnp.a', ':libcapnp.a', ':libkj.a'],
library_dirs=[
'./',
PHONELIBS + '/capnp-cpp/' + ARCH_DIR + '/lib/',
PHONELIBS + '/capnp-c/' + ARCH_DIR + '/lib/'
],
sources=['boardd_api_impl.pyx'],
language="c++",
extra_compile_args=["-std=c++11"],
)
)
)

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# This file is not used by OpenPilot. Only boardd.cc is used.
# The python version is slower, but has more options for development.
@ -15,6 +15,9 @@ from common.realtime import Ratekeeper
from selfdrive.services import service_list
from selfdrive.swaglog import cloudlog
from selfdrive.boardd.boardd import can_capnp_to_can_list
from cereal import car
SafetyModel = car.CarParams.SafetyModel
# USB is optional
try:
@ -23,13 +26,6 @@ try:
except Exception:
pass
SAFETY_NOOUTPUT = 0
SAFETY_HONDA = 1
SAFETY_TOYOTA = 2
SAFETY_CHRYSLER = 9
SAFETY_TOYOTA_NOLIMITS = 0x1336
SAFETY_ALLOUTPUT = 0x1337
# *** serialization functions ***
def can_list_to_can_capnp(can_msgs, msgtype='can'):
dat = messaging.new_message()
@ -41,7 +37,7 @@ def can_list_to_can_capnp(can_msgs, msgtype='can'):
cc = dat.can[i]
cc.address = can_msg[0]
cc.busTime = can_msg[1]
cc.dat = str(can_msg[2])
cc.dat = bytes(can_msg[2])
cc.src = can_msg[3]
return dat
@ -71,17 +67,17 @@ def can_send_many(arr):
for addr, _, dat, alt in arr:
if addr < 0x800: # only support 11 bit addr
snd = struct.pack("II", ((addr << 21) | 1), len(dat) | (alt << 4)) + dat
snd = snd.ljust(0x10, '\x00')
snd = snd.ljust(0x10, b'\x00')
snds.append(snd)
while 1:
try:
handle.bulkWrite(3, ''.join(snds))
handle.bulkWrite(3, b''.join(snds))
break
except (USBErrorIO, USBErrorOverflow):
cloudlog.exception("CAN: BAD SEND MANY, RETRYING")
def can_recv():
dat = ""
dat = b""
while 1:
try:
dat = handle.bulkRead(1, 0x10*256)
@ -102,10 +98,10 @@ def can_init():
if device.getVendorID() == 0xbbaa and device.getProductID() == 0xddcc:
handle = device.open()
handle.claimInterface(0)
handle.controlWrite(0x40, 0xdc, SAFETY_ALLOUTPUT, 0, b'')
handle.controlWrite(0x40, 0xdc, SafetyModel.allOutput, 0, b'')
if handle is None:
cloudlog.warn("CAN NOT FOUND")
cloudlog.warning("CAN NOT FOUND")
exit(-1)
cloudlog.info("got handle")
@ -113,7 +109,7 @@ def can_init():
def boardd_mock_loop():
can_init()
handle.controlWrite(0x40, 0xdc, SAFETY_ALLOUTPUT, 0, b'')
handle.controlWrite(0x40, 0xdc, SafetyModel.allOutput, 0, b'')
logcan = messaging.sub_sock(service_list['can'].port)
sendcan = messaging.pub_sock(service_list['sendcan'].port)
@ -124,17 +120,17 @@ def boardd_mock_loop():
snd = []
for s in snds:
snd += s
snd = filter(lambda x: x[-1] <= 2, snd)
snd_0 = len(filter(lambda x: x[-1] == 0, snd))
snd_1 = len(filter(lambda x: x[-1] == 1, snd))
snd_2 = len(filter(lambda x: x[-1] == 2, snd))
snd = list(filter(lambda x: x[-1] <= 2, snd))
snd_0 = len(list(filter(lambda x: x[-1] == 0, snd)))
snd_1 = len(list(filter(lambda x: x[-1] == 1, snd)))
snd_2 = len(list(filter(lambda x: x[-1] == 2, snd)))
can_send_many(snd)
# recv @ 100hz
can_msgs = can_recv()
got_0 = len(filter(lambda x: x[-1] == 0+0x80, can_msgs))
got_1 = len(filter(lambda x: x[-1] == 1+0x80, can_msgs))
got_2 = len(filter(lambda x: x[-1] == 2+0x80, can_msgs))
got_0 = len(list(filter(lambda x: x[-1] == 0+0x80, can_msgs)))
got_1 = len(list(filter(lambda x: x[-1] == 1+0x80, can_msgs)))
got_2 = len(list(filter(lambda x: x[-1] == 2+0x80, can_msgs)))
print("sent %3d (%3d/%3d/%3d) got %3d (%3d/%3d/%3d)" %
(len(snd), snd_0, snd_1, snd_2, len(can_msgs), got_0, got_1, got_2))
m = can_list_to_can_capnp(can_msgs, msgtype='sendcan')

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from __future__ import print_function
import time
import random
@ -9,9 +10,9 @@ if __name__ == "__main__":
while 1:
c = random.randint(0, 3)
if c == 0:
print can_recv()
print(can_recv())
elif c == 1:
print can_health()
print(can_health())
elif c == 2:
many = [[0x123, 0, "abcdef", 0]] * random.randint(1, 10)
can_send_many(many)

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
import sys
import time
import signal

View File

@ -1,7 +1,7 @@
import random
import numpy as np
import boardd_old
import selfdrive.boardd.tests.boardd_old as boardd_old
import selfdrive.boardd.boardd as boardd
from common.realtime import sec_since_boot
@ -12,7 +12,7 @@ import unittest
def generate_random_can_data_list():
can_list = []
cnt = random.randint(1, 64)
for j in xrange(cnt):
for j in range(cnt):
can_data = np.random.bytes(random.randint(1, 8))
can_list.append([random.randint(0, 128), random.randint(0, 128), can_data, random.randint(0, 128)])
return can_list, cnt
@ -20,7 +20,7 @@ def generate_random_can_data_list():
class TestBoarddApiMethods(unittest.TestCase):
def test_correctness(self):
for i in xrange(1000):
for i in range(1000):
can_list, _ = generate_random_can_data_list()
# Sendcan
@ -31,9 +31,10 @@ class TestBoarddApiMethods(unittest.TestCase):
ev_old = log.Event.from_bytes(m_old)
ev = log.Event.from_bytes(m)
self.assertEqual(ev_old.which(), ev.which())
self.assertEqual(len(ev.sendcan), len(ev_old.sendcan))
for i in xrange(len(ev.sendcan)):
for i in range(len(ev.sendcan)):
attrs = ['address', 'busTime', 'dat', 'src']
for attr in attrs:
self.assertEqual(getattr(ev.sendcan[i], attr, 'new'), getattr(ev_old.sendcan[i], attr, 'old'))
@ -47,7 +48,7 @@ class TestBoarddApiMethods(unittest.TestCase):
ev = log.Event.from_bytes(m)
self.assertEqual(ev_old.which(), ev.which())
self.assertEqual(len(ev.can), len(ev_old.can))
for i in xrange(len(ev.can)):
for i in range(len(ev.can)):
attrs = ['address', 'busTime', 'dat', 'src']
for attr in attrs:
self.assertEqual(getattr(ev.can[i], attr, 'new'), getattr(ev_old.can[i], attr, 'old'))
@ -57,14 +58,14 @@ class TestBoarddApiMethods(unittest.TestCase):
recursions = 1000
n1 = sec_since_boot()
for i in xrange(recursions):
for i in range(recursions):
boardd_old.can_list_to_can_capnp(can_list, 'sendcan').to_bytes()
n2 = sec_since_boot()
elapsed_old = n2 - n1
# print('Old API, elapsed time: {} secs'.format(elapsed_old))
n1 = sec_since_boot()
for i in xrange(recursions):
for i in range(recursions):
boardd.can_list_to_can_capnp(can_list)
n2 = sec_since_boot()
elapsed_new = n2 - n1

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
"""Run boardd with the BOARDD_LOOPBACK envvar before running this test."""
import os

View File

@ -36,7 +36,7 @@ endif
OBJDIR = obj
OPENDBC_PATH := $(shell python2 -c 'import opendbc; print opendbc.DBC_PATH')
OPENDBC_PATH := $(shell python3 -c 'import opendbc; print(opendbc.DBC_PATH)')
DBC_SOURCES := $(sort $(wildcard $(OPENDBC_PATH)/*.dbc))
DBC_OBJS := $(patsubst $(OPENDBC_PATH)/%.dbc,$(OBJDIR)/%.o,$(DBC_SOURCES))
@ -70,12 +70,12 @@ libdbc.so:: $(LIBDBC_OBJS) $(DBC_OBJS)
$(CEREAL_LIBS)
packer_impl.so: packer_impl.pyx packer_setup.py
python2 packer_setup.py build_ext --inplace
python3 packer_setup.py build_ext --inplace
rm -rf build
rm -f packer_impl.cpp
parser_pyx.so: parser_pyx_setup.py parser_pyx.pyx parser_pyx.pxd
python $< build_ext --inplace
python3 $< build_ext --inplace
rm -rf build
rm -f parser_pyx.cpp

View File

@ -1,11 +1,11 @@
from collections import defaultdict
from selfdrive.can.libdbc_py import libdbc, ffi
class CANDefine(object):
class CANDefine():
def __init__(self, dbc_name):
self.dv = defaultdict(dict)
self.dbc_name = dbc_name
self.dbc = libdbc.dbc_lookup(dbc_name)
self.dbc = libdbc.dbc_lookup(dbc_name.encode('utf8'))
num_vals = self.dbc[0].num_vals
@ -13,16 +13,16 @@ class CANDefine(object):
num_msgs = self.dbc[0].num_msgs
for i in range(num_msgs):
msg = self.dbc[0].msgs[i]
name = ffi.string(msg.name)
name = ffi.string(msg.name).decode('utf8')
address = msg.address
self.address_to_msg_name[address] = name
for i in range(num_vals):
val = self.dbc[0].vals[i]
sgname = ffi.string(val.name)
sgname = ffi.string(val.name).decode('utf8')
address = val.address
def_val = ffi.string(val.def_val)
def_val = ffi.string(val.def_val).decode('utf8')
#separate definition/value pairs
def_val = def_val.split()

View File

@ -1,4 +1,6 @@
# distutils: language = c++
# cython: c_string_encoding=ascii, language_level=3
from libc.stdint cimport uint32_t, uint64_t
from libcpp.vector cimport vector
from libcpp.map cimport map
@ -54,7 +56,7 @@ ctypedef uint64_t (*canpack_pack_vector_func)(void* inst, uint32_t address, cons
ctypedef const DBC * (*dbc_lookup_func)(const char* dbc_name)
cdef class CANPacker(object):
cdef class CANPacker():
cdef void *packer
cdef const DBC *dbc
cdef map[string, (int, int)] name_to_address_and_size
@ -66,11 +68,14 @@ cdef class CANPacker(object):
def __init__(self, dbc_name):
can_dir = os.path.dirname(os.path.abspath(__file__))
libdbc_fn = os.path.join(can_dir, "libdbc.so")
libdbc_fn = str(libdbc_fn).encode('utf8')
subprocess.check_call(["make"], cwd=can_dir)
cdef void *libdbc = dlopen(libdbc_fn, RTLD_LAZY)
self.canpack_init = <canpack_init_func>dlsym(libdbc, 'canpack_init')
self.canpack_pack_vector = <canpack_pack_vector_func>dlsym(libdbc, 'canpack_pack_vector')
self.dbc_lookup = <dbc_lookup_func>dlsym(libdbc, 'dbc_lookup')
self.packer = self.canpack_init(dbc_name)
self.dbc = self.dbc_lookup(dbc_name)
num_msgs = self.dbc[0].num_msgs
@ -82,8 +87,14 @@ cdef class CANPacker(object):
cdef uint64_t pack(self, addr, values, counter):
cdef vector[SignalPackValue] values_thing
cdef SignalPackValue spv
names = []
for name, value in values.iteritems():
spv.name = name
n = name.encode('utf8')
names.append(n) # TODO: find better way to keep reference to temp string arround
spv.name = n
spv.value = value
values_thing.push_back(spv)
@ -105,7 +116,7 @@ cdef class CANPacker(object):
addr = name_or_addr
size = self.address_to_size[name_or_addr]
else:
addr, size = self.name_to_address_and_size[name_or_addr]
addr, size = self.name_to_address_and_size[name_or_addr.encode('utf8')]
cdef uint64_t val = self.pack(addr, values, counter)
val = self.ReverseBytes(val)
return [addr, 0, (<char *>&val)[:size], bus]

View File

@ -1,5 +1,9 @@
from distutils.core import setup, Extension
from distutils.core import Extension, setup # pylint: disable=import-error,no-name-in-module
from Cython.Build import cythonize
from common.cython_hacks import BuildExtWithoutPlatformSuffix
setup(name='CAN Packer API Implementation',
cmdclass={'build_ext': BuildExtWithoutPlatformSuffix},
ext_modules=cythonize(Extension("packer_impl", ["packer_impl.pyx"], language="c++", extra_compile_args=["-std=c++11"])))

View File

@ -1,4 +1,6 @@
# distutils: language = c++
#cython: language_level=3
from libc.stdint cimport uint32_t, uint64_t, uint16_t
from libcpp.vector cimport vector
from libcpp.map cimport map

View File

@ -1,4 +1,6 @@
# distutils: language = c++
# cython: c_string_encoding=ascii, language_level=3
from posix.dlfcn cimport dlopen, dlsym, RTLD_LAZY
from libcpp cimport bool
@ -8,10 +10,11 @@ import numbers
cdef int CAN_INVALID_CNT = 5
cdef class CANParser:
def __init__(self, dbc_name, signals, checks=None, bus=0, sendcan=False, tcp_addr="", timeout=-1):
def __init__(self, dbc_name, signals, checks=None, bus=0, sendcan=False, tcp_addr=b"", timeout=-1):
self.test_mode_enabled = False
can_dir = os.path.dirname(os.path.abspath(__file__))
libdbc_fn = os.path.join(can_dir, "libdbc.so")
libdbc_fn = str(libdbc_fn).encode('utf8')
cdef void *libdbc = dlopen(libdbc_fn, RTLD_LAZY)
self.can_init_with_vectors = <can_init_with_vectors_func>dlsym(libdbc, 'can_init_with_vectors')
@ -33,24 +36,28 @@ cdef class CANParser:
num_msgs = self.dbc[0].num_msgs
for i in range(num_msgs):
msg = self.dbc[0].msgs[i]
self.msg_name_to_address[string(msg.name)] = msg.address
self.address_to_msg_name[msg.address] = string(msg.name)
name = msg.name.decode('utf8')
self.msg_name_to_address[name] = msg.address
self.address_to_msg_name[msg.address] = name
self.vl[msg.address] = {}
self.vl[str(msg.name)] = {}
self.vl[name] = {}
self.ts[msg.address] = {}
self.ts[str(msg.name)] = {}
self.ts[name] = {}
# Convert message names into addresses
for i in range(len(signals)):
s = signals[i]
if not isinstance(s[1], numbers.Number):
s = (s[0], self.msg_name_to_address[s[1]], s[2])
name = s[1].encode('utf8')
s = (s[0], self.msg_name_to_address[name], s[2])
signals[i] = s
for i in range(len(checks)):
c = checks[i]
if not isinstance(c[0], numbers.Number):
c = (self.msg_name_to_address[c[0]], c[1])
name = c[0].encode('utf8')
c = (self.msg_name_to_address[name], c[1])
checks[i] = c
cdef vector[SignalParseOptions] signal_options_v
@ -89,12 +96,15 @@ cdef class CANParser:
for cv in self.can_values:
self.vl[cv.address][string(cv.name)] = cv.value
self.ts[cv.address][string(cv.name)] = cv.ts
# Cast char * directly to unicde
name = <unicode>self.address_to_msg_name[cv.address].c_str()
cv_name = <unicode>cv.name
sig_name = self.address_to_msg_name[cv.address]
self.vl[sig_name][string(cv.name)] = cv.value
self.ts[sig_name][string(cv.name)] = cv.ts
self.vl[cv.address][cv_name] = cv.value
self.ts[cv.address][cv_name] = cv.ts
self.vl[name][cv_name] = cv.value
self.ts[name][cv_name] = cv.ts
updated_val.insert(cv.address)

View File

@ -1,14 +1,19 @@
from distutils.core import setup, Extension
from Cython.Build import cythonize
import subprocess
from distutils.core import Extension, setup # pylint: disable=import-error,no-name-in-module
from Cython.Build import cythonize
from common.cython_hacks import BuildExtWithoutPlatformSuffix
sourcefiles = ['parser_pyx.pyx']
extra_compile_args = ["-std=c++11"]
ARCH = subprocess.check_output(["uname", "-m"]).rstrip()
ARCH = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip() # pylint: disable=unexpected-keyword-arg
if ARCH == "aarch64":
extra_compile_args += ["-Wno-deprecated-register"]
setup(name='Radard Thread',
cmdclass={'build_ext': BuildExtWithoutPlatformSuffix},
ext_modules=cythonize(
Extension(
"parser_pyx",

View File

@ -7,7 +7,7 @@ from selfdrive.car.honda.hondacan import fix
from common.realtime import sec_since_boot
from common.dbc import dbc
class CANParser(object):
class CANParser():
def __init__(self, dbc_f, signals, checks=None):
### input:
# dbc_f : dbc file
@ -73,7 +73,7 @@ class CANParser(object):
self.ck[msg] = True
if "CHECKSUM" in out.keys() and msg in self.msgs_ck:
# remove checksum (half byte)
ck_portion = cdat[:-1] + chr(ord(cdat[-1]) & 0xF0)
ck_portion = cdat[:-1] + (cdat[-1] & 0xF0).to_bytes(1, 'little')
# recalculate checksum
msg_vl = fix(ck_portion, msg)
# compare recalculated vs received checksum

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python2
#!/usr/bin/env python3
from __future__ import print_function
import os
import glob
import sys
@ -10,7 +11,7 @@ from common.dbc import dbc
def main():
if len(sys.argv) != 3:
print "usage: %s dbc_directory output_directory" % (sys.argv[0],)
print("usage: %s dbc_directory output_directory" % (sys.argv[0],))
sys.exit(0)
dbc_dir = sys.argv[1]
@ -38,7 +39,7 @@ def main():
if dbc_mtime < out_mtime and template_mtime < out_mtime and this_file_mtime < out_mtime:
continue #skip output is newer than template and dbc
msgs = [(address, msg_name, msg_size, sorted(msg_sigs, key=lambda s: s.name not in ("COUNTER", "CHECKSUM"))) # process counter and checksums first
msgs = [(address, msg_name, msg_size, sorted(msg_sigs, key=lambda s: s.name not in (b"COUNTER", b"CHECKSUM"))) # process counter and checksums first
for address, ((msg_name, msg_size), msg_sigs) in sorted(can_dbc.msgs.items()) if msg_sigs]
def_vals = {a: set(b) for a,b in can_dbc.def_vals.items()} #remove duplicates
@ -55,22 +56,22 @@ def main():
for address, msg_name, msg_size, sigs in msgs:
for sig in sigs:
if checksum_type is not None and sig.name == "CHECKSUM":
if checksum_type is not None and sig.name == b"CHECKSUM":
if sig.size != checksum_size:
sys.exit("CHECKSUM is not %d bits longs %s" % (checksum_size, msg_name))
if checksum_type == "honda" and sig.start_bit % 8 != 3:
sys.exit("CHECKSUM starts at wrong bit %s" % msg_name)
if checksum_type == "toyota" and sig.start_bit % 8 != 7:
sys.exit("CHECKSUM starts at wrong bit %s" % msg_name)
if checksum_type == "honda" and sig.name == "COUNTER":
if checksum_type == "honda" and sig.name == b"COUNTER":
if sig.size != 2:
sys.exit("COUNTER is not 2 bits longs %s" % msg_name)
if sig.start_bit % 8 != 5:
sys.exit("COUNTER starts at wrong bit %s" % msg_name)
if address in [0x200, 0x201]:
if sig.name == "COUNTER_PEDAL" and sig.size != 4:
if sig.name == b"COUNTER_PEDAL" and sig.size != 4:
sys.exit("PEDAL COUNTER is not 4 bits longs %s" % msg_name)
if sig.name == "CHECKSUM_PEDAL" and sig.size != 8:
if sig.name == b"CHECKSUM_PEDAL" and sig.size != 8:
sys.exit("PEDAL CHECKSUM is not 8 bits longs %s" % msg_name)
# Fail on duplicate message names

View File

@ -2,8 +2,9 @@ import struct
from selfdrive.can.libdbc_py import libdbc, ffi
class CANPacker(object):
class CANPacker():
def __init__(self, dbc_name):
dbc_name = dbc_name.encode('utf8')
self.packer = libdbc.canpack_init(dbc_name)
self.dbc = libdbc.dbc_lookup(dbc_name)
self.sig_names = {}
@ -13,16 +14,16 @@ class CANPacker(object):
for i in range(num_msgs):
msg = self.dbc[0].msgs[i]
name = ffi.string(msg.name)
name = ffi.string(msg.name).decode('utf8')
address = msg.address
self.name_to_address_and_size[name] = (address, msg.size)
self.name_to_address_and_size[address] = (address, msg.size)
def pack(self, addr, values, counter):
values_thing = []
for name, value in values.iteritems():
for name, value in values.items():
if name not in self.sig_names:
self.sig_names[name] = ffi.new("char[]", name)
self.sig_names[name] = ffi.new("char[]", name.encode('utf8'))
values_thing.append({
'name': self.sig_names[name],

View File

@ -5,7 +5,7 @@ from selfdrive.can.libdbc_py import libdbc, ffi
CAN_INVALID_CNT = 5 # after so many consecutive CAN data with wrong checksum, counter or frequency, flag CAN invalidity
class CANParser(object):
class CANParser():
def __init__(self, dbc_name, signals, checks=None, bus=0, sendcan=False, tcp_addr="127.0.0.1", timeout=-1):
if checks is None:
checks = []
@ -16,7 +16,7 @@ class CANParser(object):
self.ts = {}
self.dbc_name = dbc_name
self.dbc = libdbc.dbc_lookup(dbc_name)
self.dbc = libdbc.dbc_lookup(dbc_name.encode('utf8'))
self.msg_name_to_addres = {}
self.address_to_msg_name = {}
@ -24,7 +24,7 @@ class CANParser(object):
for i in range(num_msgs):
msg = self.dbc[0].msgs[i]
name = ffi.string(msg.name)
name = ffi.string(msg.name).decode('utf8')
address = msg.address
self.msg_name_to_addres[name] = address
@ -48,7 +48,7 @@ class CANParser(object):
c = (self.msg_name_to_addres[c[0]], c[1])
checks[i] = c
sig_names = dict((name, ffi.new("char[]", name)) for name, _, _ in signals)
sig_names = dict((name, ffi.new("char[]", name.encode('utf8'))) for name, _, _ in signals)
signal_options_c = ffi.new("SignalParseOptions[]", [
{
@ -66,8 +66,8 @@ class CANParser(object):
'check_frequency': freq,
} for msg_address, freq in message_options.items()])
self.can = libdbc.can_init(bus, dbc_name, len(message_options_c), message_options_c,
len(signal_options_c), signal_options_c, sendcan, tcp_addr, timeout)
self.can = libdbc.can_init(bus, dbc_name.encode('utf8'), len(message_options_c), message_options_c,
len(signal_options_c), signal_options_c, sendcan, tcp_addr.encode('utf8'), timeout)
self.p_can_valid = ffi.new("bool*")
@ -85,11 +85,11 @@ class CANParser(object):
self.can_valid = self.can_invalid_cnt < CAN_INVALID_CNT
ret = set()
for i in xrange(can_values_len):
for i in range(can_values_len):
cv = self.can_values[i]
address = cv.address
# print("{0} {1}".format(hex(cv.address), ffi.string(cv.name)))
name = ffi.string(cv.name)
name = ffi.string(cv.name).decode('utf8')
self.vl[address][name] = cv.value
self.ts[address][name] = cv.ts

View File

@ -13,7 +13,7 @@ class TestPackerMethods(unittest.TestCase):
def test_correctness(self):
# Test all commands, randomize the params.
for _ in xrange(1000):
for _ in range(1000):
gear = ('drive', 'reverse', 'low')[random.randint(0, 3) % 3]
lkas_active = (random.randint(0, 2) % 2 == 0)
hud_alert = random.randint(0, 6)

View File

@ -17,7 +17,7 @@ class TestPackerMethods(unittest.TestCase):
def test_correctness(self):
# Test all cars' commands, randomize the params.
for _ in xrange(1000):
for _ in range(1000):
bus = random.randint(0, 65536)
apply_steer = (random.randint(0, 2) % 2 == 0)
idx = random.randint(0, 65536)

View File

@ -15,8 +15,8 @@ class TestPackerMethods(unittest.TestCase):
def test_correctness(self):
# Test all commands, randomize the params.
for _ in xrange(1000):
is_panda_black = False
for _ in range(1000):
has_relay = False
car_fingerprint = HONDA_BOSCH[0]
apply_brake = (random.randint(0, 2) % 2 == 0)
@ -25,15 +25,15 @@ class TestPackerMethods(unittest.TestCase):
pcm_cancel_cmd = (random.randint(0, 2) % 2 == 0)
fcw = random.randint(0, 65536)
idx = random.randint(0, 65536)
m_old = hondacan.create_brake_command(self.honda_cp_old, apply_brake, pump_on, pcm_override, pcm_cancel_cmd, fcw, idx, car_fingerprint, is_panda_black)
m = hondacan.create_brake_command(self.honda_cp, apply_brake, pump_on, pcm_override, pcm_cancel_cmd, fcw, idx, car_fingerprint, is_panda_black)
m_old = hondacan.create_brake_command(self.honda_cp_old, apply_brake, pump_on, pcm_override, pcm_cancel_cmd, fcw, idx, car_fingerprint, has_relay)
m = hondacan.create_brake_command(self.honda_cp, apply_brake, pump_on, pcm_override, pcm_cancel_cmd, fcw, idx, car_fingerprint, has_relay)
self.assertEqual(m_old, m)
apply_steer = (random.randint(0, 2) % 2 == 0)
lkas_active = (random.randint(0, 2) % 2 == 0)
idx = random.randint(0, 65536)
m_old = hondacan.create_steering_control(self.honda_cp_old, apply_steer, lkas_active, car_fingerprint, idx, is_panda_black)
m = hondacan.create_steering_control(self.honda_cp, apply_steer, lkas_active, car_fingerprint, idx, is_panda_black)
m_old = hondacan.create_steering_control(self.honda_cp_old, apply_steer, lkas_active, car_fingerprint, idx, has_relay)
m = hondacan.create_steering_control(self.honda_cp, apply_steer, lkas_active, car_fingerprint, idx, has_relay)
self.assertEqual(m_old, m)
pcm_speed = random.randint(0, 65536)
@ -41,14 +41,14 @@ class TestPackerMethods(unittest.TestCase):
0xc1, random.randint(0, 65536), random.randint(0, 65536), random.randint(0, 65536), random.randint(0, 65536))
idx = random.randint(0, 65536)
is_metric = (random.randint(0, 2) % 2 == 0)
m_old = hondacan.create_ui_commands(self.honda_cp_old, pcm_speed, hud, car_fingerprint, is_metric, idx, is_panda_black)
m = hondacan.create_ui_commands(self.honda_cp, pcm_speed, hud, car_fingerprint, is_metric, idx, is_panda_black)
m_old = hondacan.create_ui_commands(self.honda_cp_old, pcm_speed, hud, car_fingerprint, is_metric, idx, has_relay)
m = hondacan.create_ui_commands(self.honda_cp, pcm_speed, hud, car_fingerprint, is_metric, idx, has_relay)
self.assertEqual(m_old, m)
button_val = random.randint(0, 65536)
idx = random.randint(0, 65536)
m_old = hondacan.spam_buttons_command(self.honda_cp_old, button_val, idx, car_fingerprint, is_panda_black)
m = hondacan.spam_buttons_command(self.honda_cp, button_val, idx, car_fingerprint, is_panda_black)
m_old = hondacan.spam_buttons_command(self.honda_cp_old, button_val, idx, car_fingerprint, has_relay)
m = hondacan.spam_buttons_command(self.honda_cp, button_val, idx, car_fingerprint, has_relay)
self.assertEqual(m_old, m)

View File

@ -14,7 +14,7 @@ class TestPackerMethods(unittest.TestCase):
def test_correctness(self):
# Test all commands, randomize the params.
for _ in xrange(1000):
for _ in range(1000):
# Hyundai
car_fingerprint = hyundai_checksum["crc8"][0]
apply_steer = (random.randint(0, 2) % 2 == 0)

View File

@ -14,7 +14,7 @@ class TestPackerMethods(unittest.TestCase):
def test_correctness(self):
# Test all cars' commands, randomize the params.
for _ in xrange(1000):
for _ in range(1000):
apply_steer = (random.randint(0, 2) % 2 == 0)
frame = random.randint(1, 65536)
steer_step = random.randint(1, 65536)

View File

@ -17,7 +17,7 @@ class TestPackerMethods(unittest.TestCase):
def test_correctness(self):
# Test all commands, randomize the params.
for _ in xrange(1000):
for _ in range(1000):
# Toyota
steer = random.randint(-1, 1)
enabled = (random.randint(0, 2) % 2 == 0)
@ -66,14 +66,14 @@ class TestPackerMethods(unittest.TestCase):
left_lane_depart = (random.randint(0, 2) % 2 == 0)
right_lane_depart = (random.randint(0, 2) % 2 == 0)
for _ in xrange(recursions):
for _ in range(recursions):
create_ui_command(self.cp_old, steer, chime, left_line, right_line, left_lane_depart, right_lane_depart)
n2 = sec_since_boot()
elapsed_old = n2 - n1
# print('Old API, elapsed time: {} secs'.format(elapsed_old))
n1 = sec_since_boot()
for _ in xrange(recursions):
for _ in range(recursions):
create_ui_command(self.cp, steer, chime, left_line, right_line, left_lane_depart, right_lane_depart)
n2 = sec_since_boot()
elapsed_new = n2 - n1

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python2
#!/usr/bin/env python3
import os
import unittest
@ -45,7 +45,7 @@ def dicts_vals_differ(dict1, dict2):
def run_route(route):
can = messaging.pub_sock(service_list['can'].port)
CP = CarInterface.get_params(CAR.CIVIC, {})
CP = CarInterface.get_params(CAR.CIVIC)
signals, checks = get_can_signals(CP)
parser_old = CANParserOld(DBC[CP.carFingerprint]['pt'], signals, checks, 0, timeout=-1, tcp_addr="127.0.0.1")
parser_new = CANParserNew(DBC[CP.carFingerprint]['pt'], signals, checks, 0, timeout=-1, tcp_addr="127.0.0.1")
@ -95,7 +95,7 @@ class TestCanParser(unittest.TestCase):
for route in self.routes.values():
route_filename = route + ".bz2"
if not os.path.isfile(route_filename):
with open(route + ".bz2", "w") as f:
with open(route + ".bz2", "wb") as f:
f.write(requests.get(BASE_URL + route_filename).content)
def test_parser_civic(self):

View File

@ -4,6 +4,9 @@ from common.numpy_fast import clip
# kg of standard extra cargo to count for drive, gas, etc...
STD_CARGO_KG = 136.
def gen_empty_fingerprint():
return {i: {} for i in range(0, 4)}
# FIXME: hardcoding honda civic 2016 touring params so they can be used to
# scale unknown params for other cars
class CivicParams:
@ -31,7 +34,7 @@ def scale_tire_stiffness(mass, wheelbase, center_to_front, tire_stiffness_factor
(center_to_front / wheelbase) / (CivicParams.CENTER_TO_FRONT / CivicParams.WHEELBASE)
return tire_stiffness_front, tire_stiffness_rear
def dbc_dict(pt_dbc, radar_dbc, chassis_dbc=None):
return {'pt': pt_dbc, 'radar': radar_dbc, 'chassis': chassis_dbc}
@ -53,11 +56,10 @@ def apply_std_steer_torque_limits(apply_torque, apply_torque_last, driver_torque
apply_torque = clip(apply_torque, apply_torque_last - LIMITS.STEER_DELTA_UP,
min(apply_torque_last + LIMITS.STEER_DELTA_DOWN, LIMITS.STEER_DELTA_UP))
return int(round(apply_torque))
return int(round(float(apply_torque)))
def apply_toyota_steer_torque_limits(apply_torque, apply_torque_last, motor_torque, LIMITS):
# limits due to comparison of commanded torque VS motor reported torque
max_lim = min(max(motor_torque + LIMITS.STEER_ERROR_MAX, LIMITS.STEER_ERROR_MAX), LIMITS.STEER_MAX)
min_lim = max(min(motor_torque - LIMITS.STEER_ERROR_MAX, -LIMITS.STEER_ERROR_MAX), -LIMITS.STEER_MAX)
@ -74,7 +76,7 @@ def apply_toyota_steer_torque_limits(apply_torque, apply_torque_last, motor_torq
apply_torque_last - LIMITS.STEER_DELTA_UP,
min(apply_torque_last + LIMITS.STEER_DELTA_DOWN, LIMITS.STEER_DELTA_UP))
return int(round(apply_torque))
return int(round(float(apply_torque)))
def crc8_pedal(data):
@ -106,8 +108,19 @@ def create_gas_command(packer, gas_amount, idx):
dat = packer.make_can_msg("GAS_COMMAND", 0, values)[2]
dat = [ord(i) for i in dat]
checksum = crc8_pedal(dat[:-1])
values["CHECKSUM_PEDAL"] = checksum
return packer.make_can_msg("GAS_COMMAND", 0, values)
def is_ecu_disconnected(fingerprint, fingerprint_list, ecu_fingerprint, car, ecu):
# check if a stock ecu is disconnected by looking for specific CAN msgs in the fingerprint
# return True if the reference car fingerprint contains the ecu fingerprint msg and
# fingerprint does not contains messages normally sent by a given ecu
ecu_in_car = False
for car_finger in fingerprint_list[car]:
if any(msg in car_finger for msg in ecu_fingerprint[ecu]):
ecu_in_car = True
return ecu_in_car and not any(msg in fingerprint for msg in ecu_fingerprint[ecu])

View File

@ -2,11 +2,12 @@ import os
import zmq
from cereal import car
from common.params import Params
from common.vin import get_vin, VIN_UNKNOWN
from common.basedir import BASEDIR
from common.fingerprints import eliminate_incompatible_cars, all_known_cars
from selfdrive.car.fingerprints import eliminate_incompatible_cars, all_known_cars
from selfdrive.car.vin import get_vin, VIN_UNKNOWN
from selfdrive.swaglog import cloudlog
import selfdrive.messaging as messaging
from selfdrive.car import gen_empty_fingerprint
def get_one_can(logcan):
@ -67,12 +68,7 @@ def only_toyota_left(candidate_cars):
# BOUNTY: every added fingerprint in selfdrive/car/*/values.py is a $100 coupon code on shop.comma.ai
# **** for use live only ****
def fingerprint(logcan, sendcan, is_panda_black):
if os.getenv("SIMULATOR2") is not None:
return ("simulator2", None, "")
elif os.getenv("SIMULATOR") is not None:
return ("simulator", None, "")
def fingerprint(logcan, sendcan, has_relay):
params = Params()
car_params = params.get("CarParams")
@ -80,7 +76,7 @@ def fingerprint(logcan, sendcan, is_panda_black):
# use already stored VIN: a new VIN query cannot be done, since panda isn't in ELM327 mode
car_params = car.CarParams.from_bytes(car_params)
vin = VIN_UNKNOWN if car_params.carVin == "" else car_params.carVin
elif is_panda_black:
elif has_relay:
# Vin query only reliably works thorugh OBDII
vin = get_vin(logcan, sendcan, 1)
else:
@ -89,7 +85,7 @@ def fingerprint(logcan, sendcan, is_panda_black):
cloudlog.warning("VIN %s", vin)
Params().put("CarVin", vin)
finger = {i: {} for i in range(0, 4)} # collect on all buses
finger = gen_empty_fingerprint()
candidate_cars = {i: all_known_cars() for i in [0, 1]} # attempt fingerprint on both bus 0 and 1
frame = 0
frame_fingerprint = 10 # 0.1s
@ -105,10 +101,11 @@ def fingerprint(logcan, sendcan, is_panda_black):
# and VIN query response.
# Include bus 2 for toyotas to disambiguate cars using camera messages
# (ideally should be done for all cars but we can't for Honda Bosch)
if can.src in range(0, 4):
finger[can.src][can.address] = len(can.dat)
for b in candidate_cars:
if (can.src == b or (only_toyota_left(candidate_cars[b]) and can.src == 2)) and \
can.address < 0x800 and can.address not in [0x7df, 0x7e0, 0x7e8]:
finger[can.src][can.address] = len(can.dat)
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
@ -123,7 +120,7 @@ def fingerprint(logcan, sendcan, is_panda_black):
car_fingerprint = candidate_cars[b][0]
# bail if no cars left or we've been waiting for more than 2s
failed = all(len(cc) == 0 for cc in candidate_cars.itervalues()) or frame > 200
failed = all(len(cc) == 0 for cc in candidate_cars.values()) or frame > 200
succeeded = car_fingerprint is not None
done = failed or succeeded
@ -133,15 +130,15 @@ def fingerprint(logcan, sendcan, is_panda_black):
return car_fingerprint, finger, vin
def get_car(logcan, sendcan, is_panda_black=False):
def get_car(logcan, sendcan, has_relay=False):
candidate, fingerprints, vin = fingerprint(logcan, sendcan, is_panda_black)
candidate, fingerprints, vin = fingerprint(logcan, sendcan, has_relay)
if candidate is None:
cloudlog.warning("car doesn't match any fingerprints: %r", fingerprints)
candidate = "mock"
CarInterface, CarController = interfaces[candidate]
car_params = CarInterface.get_params(candidate, fingerprints[0], vin, is_panda_black)
car_params = CarInterface.get_params(candidate, fingerprints, vin, has_relay)
return CarInterface(car_params, CarController), car_params

View File

@ -11,7 +11,7 @@ class SteerLimitParams:
STEER_ERROR_MAX = 80
class CarController(object):
class CarController():
def __init__(self, dbc_name, car_fingerprint, enable_camera):
self.braking = False
# redundant safety check with the board

View File

@ -77,7 +77,7 @@ def get_camera_parser(CP):
return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 2)
class CarState(object):
class CarState():
def __init__(self, CP):
self.CP = CP

View File

@ -1,6 +1,7 @@
from cereal import car
GearShifter = car.CarState.GearShifter
VisualAlert = car.CarControl.HUDControl.VisualAlert
def calc_checksum(data):
@ -48,7 +49,7 @@ def create_lkas_hud(packer, gear, lkas_active, hud_alert, hud_count, lkas_car_mo
# LKAS_HUD 0x2a6 (678) Controls what lane-keeping icon is displayed.
if hud_alert == VisualAlert.steerRequired:
msg = '0000000300000000'.decode('hex')
msg = b'\x00\x00\x00\x03\x00\x00\x00\x00'
return make_can_msg(0x2a6, msg)
color = 1 # default values are for park or neutral in 2017 are 0 0, but trying 1 1 for 2019
@ -59,7 +60,7 @@ def create_lkas_hud(packer, gear, lkas_active, hud_alert, hud_count, lkas_car_mo
alerts = 1
# CAR.PACIFICA_2018_HYBRID and CAR.PACIFICA_2019_HYBRID
# had color = 1 and lines = 1 but trying 2017 hybrid style for now.
if gear in ('drive', 'reverse', 'low'):
if gear in (GearShifter.drive, GearShifter.reverse, GearShifter.low):
if lkas_active:
color = 2 # control active, display green.
lines = 6
@ -86,7 +87,7 @@ def create_lkas_command(packer, apply_steer, moving_fast, frame):
}
dat = packer.make_can_msg("LKAS_COMMAND", 0, values)[2]
dat = [ord(i) for i in dat][:-1]
dat = dat[:-1]
checksum = calc_checksum(dat)
values["CHECKSUM"] = checksum
@ -95,8 +96,8 @@ def create_lkas_command(packer, apply_steer, moving_fast, frame):
def create_wheel_buttons(frame):
# WHEEL_BUTTONS (571) Message sent to cancel ACC.
start = [0x01] # acc cancel set
start = b"\x01" # acc cancel set
counter = (frame % 10) << 4
dat = start + [counter]
dat = dat + [calc_checksum(dat)]
return make_can_msg(0x23b, str(bytearray(dat)))
dat = start + counter.to_bytes(1, 'little')
dat = dat + calc_checksum(dat).to_bytes(1, 'little')
return make_can_msg(0x23b, dat)

View File

@ -1,16 +1,17 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from cereal import car
from selfdrive.config import Conversions as CV
from selfdrive.controls.lib.drive_helpers import EventTypes as ET, create_event
from selfdrive.controls.lib.vehicle_model import VehicleModel
from selfdrive.car.chrysler.carstate import CarState, get_can_parser, get_camera_parser
from selfdrive.car.chrysler.values import ECU, check_ecu_msgs, CAR
from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness
from selfdrive.car.chrysler.values import ECU, ECU_FINGERPRINT, CAR, FINGERPRINTS
from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, is_ecu_disconnected, gen_empty_fingerprint
from selfdrive.car.interfaces import CarInterfaceBase
GearShifter = car.CarState.GearShifter
ButtonType = car.CarState.ButtonEvent.Type
class CarInterface(object):
class CarInterface(CarInterfaceBase):
def __init__(self, CP, CarController):
self.CP = CP
self.VM = VehicleModel(CP)
@ -34,18 +35,14 @@ class CarInterface(object):
return float(accel) / 3.0
@staticmethod
def calc_accel_override(a_ego, a_target, v_ego, v_target):
return 1.0
@staticmethod
def get_params(candidate, fingerprint, vin="", is_panda_black=False):
def get_params(candidate, fingerprint=gen_empty_fingerprint(), vin="", has_relay=False):
ret = car.CarParams.new_message()
ret.carName = "chrysler"
ret.carFingerprint = candidate
ret.carVin = vin
ret.isPandaBlack = is_panda_black
ret.isPandaBlack = has_relay
ret.safetyModel = car.CarParams.SafetyModel.chrysler
@ -95,7 +92,7 @@ class CarInterface(object):
ret.brakeMaxBP = [5., 20.]
ret.brakeMaxV = [1., 0.8]
ret.enableCamera = not check_ecu_msgs(fingerprint, ECU.CAM) or is_panda_black
ret.enableCamera = is_ecu_disconnected(fingerprint[0], FINGERPRINTS, ECU_FINGERPRINT, candidate, ECU.CAM) or has_relay
print("ECU Camera Simulated: {0}".format(ret.enableCamera))
ret.openpilotLongitudinalControl = False

View File

@ -1,10 +1,11 @@
#!/usr/bin/env python
#!/usr/bin/env python3
import os
from selfdrive.can.parser import CANParser
from cereal import car
from selfdrive.car.interfaces import RadarInterfaceBase
RADAR_MSGS_C = range(0x2c2, 0x2d4+2, 2) # c_ messages 706,...,724
RADAR_MSGS_D = range(0x2a2, 0x2b4+2, 2) # d_ messages
RADAR_MSGS_C = list(range(0x2c2, 0x2d4+2, 2)) # c_ messages 706,...,724
RADAR_MSGS_D = list(range(0x2a2, 0x2b4+2, 2)) # d_ messages
LAST_MSG = max(RADAR_MSGS_C + RADAR_MSGS_D)
NUMBER_MSGS = len(RADAR_MSGS_C) + len(RADAR_MSGS_D)
@ -45,10 +46,10 @@ def _address_to_track(address):
return (address - RADAR_MSGS_D[0]) // 2
raise ValueError("radar received unexpected address %d" % address)
class RadarInterface(object):
class RadarInterface(RadarInterfaceBase):
def __init__(self, CP):
self.pts = {}
self.delay = 0.0 # Delay of radar #TUNE
self.delay = 0 # Delay of radar #TUNE
self.rcp = _create_radar_can_parser()
self.updated_messages = set()
self.trigger_msg = LAST_MSG

View File

@ -1 +0,0 @@
PYTHONPATH=`realpath ../../../` python chryslercan_test.py

View File

@ -1,55 +1,57 @@
from selfdrive.car.chrysler import chryslercan
from selfdrive.can.packer import CANPacker
import unittest
from cereal import car
VisualAlert = car.CarControl.HUDControl.VisualAlert
from selfdrive.can.packer import CANPacker
from selfdrive.car.chrysler import chryslercan
VisualAlert = car.CarControl.HUDControl.VisualAlert
GearShifter = car.CarState.GearShifter
import unittest
class TestChryslerCan(unittest.TestCase):
def test_checksum(self):
self.assertEqual(0x75, chryslercan.calc_checksum([0x01, 0x20]))
self.assertEqual(0xcc, chryslercan.calc_checksum([0x14, 0, 0, 0, 0x20]))
self.assertEqual(0x75, chryslercan.calc_checksum(b"\x01\x20"))
self.assertEqual(0xcc, chryslercan.calc_checksum(b"\x14\x00\x00\x00\x20"))
def test_hud(self):
packer = CANPacker('chrysler_pacifica_2017_hybrid')
self.assertEqual(
[0x2a6, 0, '0100010100000000'.decode('hex'), 0],
[0x2a6, 0, b'\x01\x00\x01\x01\x00\x00\x00\x00', 0],
chryslercan.create_lkas_hud(
packer,
'park', False, False, 1, 0))
GearShifter.park, False, False, 1, 0))
self.assertEqual(
[0x2a6, 0, '0100010000000000'.decode('hex'), 0],
[0x2a6, 0, b'\x01\x00\x01\x00\x00\x00\x00\x00', 0],
chryslercan.create_lkas_hud(
packer,
'park', False, False, 5*4, 0))
GearShifter.park, False, False, 5*4, 0))
self.assertEqual(
[0x2a6, 0, '0100010000000000'.decode('hex'), 0],
[0x2a6, 0, b'\x01\x00\x01\x00\x00\x00\x00\x00', 0],
chryslercan.create_lkas_hud(
packer,
'park', False, False, 99999, 0))
GearShifter.park, False, False, 99999, 0))
self.assertEqual(
[0x2a6, 0, '0200060000000000'.decode('hex'), 0],
[0x2a6, 0, b'\x02\x00\x06\x00\x00\x00\x00\x00', 0],
chryslercan.create_lkas_hud(
packer,
'drive', True, False, 99999, 0))
GearShifter.drive, True, False, 99999, 0))
self.assertEqual(
[0x2a6, 0, '0264060000000000'.decode('hex'), 0],
[0x2a6, 0, b'\x02\x64\x06\x00\x00\x00\x00\x00', 0],
chryslercan.create_lkas_hud(
packer,
'drive', True, False, 99999, 0x64))
GearShifter.drive, True, False, 99999, 0x64))
def test_command(self):
packer = CANPacker('chrysler_pacifica_2017_hybrid')
self.assertEqual(
[0x292, 0, '140000001086'.decode('hex'), 0],
[0x292, 0, b'\x14\x00\x00\x00\x10\x86', 0],
chryslercan.create_lkas_command(
packer,
0, True, 1))
self.assertEqual(
[0x292, 0, '040000008083'.decode('hex'), 0],
[0x292, 0, b'\x04\x00\x00\x00\x80\x83', 0],
chryslercan.create_lkas_command(
packer,
0, False, 8))

View File

@ -4,7 +4,7 @@ class CAR:
PACIFICA_2017_HYBRID = "CHRYSLER PACIFICA HYBRID 2017"
PACIFICA_2018_HYBRID = "CHRYSLER PACIFICA HYBRID 2018"
PACIFICA_2019_HYBRID = "CHRYSLER PACIFICA HYBRID 2019"
PACIFICA_2018 = "CHRYSLER PACIFICA 2018"
PACIFICA_2018 = "CHRYSLER PACIFICA 2018" # Also covers Pacifica 2017.
JEEP_CHEROKEE = "JEEP GRAND CHEROKEE V6 2018" # Also covers Tailhawk 2017.
JEEP_CHEROKEE_2019 = "JEEP GRAND CHEROKEE 2019"
@ -25,14 +25,15 @@ FINGERPRINTS = {
],
CAR.PACIFICA_2018: [
{55: 8, 257: 5, 258: 8, 264: 8, 268: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 368: 8, 376: 3, 384: 8, 388: 4, 416: 7, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 516: 7, 517: 7, 520: 8, 524: 8, 526: 6, 528: 8, 532: 8, 542: 8, 544: 8, 557: 8, 559: 8, 560: 4, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 656: 4, 658: 6, 660: 8, 669: 3, 671: 8, 672: 8, 678: 8, 680: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 746: 5, 752: 2, 760: 8, 764: 8, 766: 8, 770: 8, 773: 8, 779: 8, 784: 8, 792: 8, 799: 8, 800: 8, 804: 8, 808: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 882: 8, 897: 8, 924: 8, 926: 3, 937: 8, 947: 8, 948: 8, 969: 4, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1098: 8, 1100: 8, 1537: 8, 1538: 8, 1562: 8},
{55: 8, 257: 5, 258: 8, 264: 8, 268: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 368: 8, 376: 3, 384: 8, 388: 4, 416: 7, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 516: 7, 517: 7, 520: 8, 524: 8, 526: 6, 528: 8, 532: 8, 542: 8, 544: 8, 557: 8, 559: 8, 560: 4, 564: 4, 571: 3, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 656: 4, 658: 6, 660: 8, 669: 3, 671: 8, 672: 8, 678: 8, 680: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 746: 5, 752: 2, 760: 8, 764: 8, 766: 8, 770: 8, 773: 8, 779: 8, 784: 8, 792: 8, 799: 8, 800: 8, 804: 8, 808: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 882: 8, 897: 8, 924: 3, 926: 3, 937: 8, 947: 8, 948: 8, 969: 4, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1098: 8, 1100: 8, 1537: 8, 1538: 8, 1562: 8},
],
CAR.PACIFICA_2018_HYBRID: [
{68: 8, 168: 8, 257: 5, 258: 8, 264: 8, 268: 8, 270: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 291: 8, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 368: 8, 376: 3, 384: 8, 388: 4, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 520: 8, 528: 8, 532: 8, 544: 8, 557: 8, 559: 8, 560: 4, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 653: 8, 654: 8, 655: 8, 660: 8, 669: 3, 671: 8, 672: 8, 680: 8, 701: 8, 704: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 736: 8, 737: 8, 746: 5, 760: 8, 764: 8, 766: 8, 770: 8, 773: 8, 779: 8, 782: 8, 784: 8, 792: 8, 799: 8, 800: 8, 804: 8, 808: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 878: 8, 882: 8, 897: 8, 908: 8, 924: 8, 926: 3, 929: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 958: 8, 959: 8, 969: 4, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1082: 8, 1083: 8, 1098: 8, 1100: 8},
{68: 8, 168: 8, 257: 5, 258: 8, 264: 8, 268: 8, 270: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 291: 8, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 368: 8, 376: 3, 384: 8, 388: 4, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 520: 8, 528: 8, 532: 8, 544: 8, 557: 8, 559: 8, 560: 4, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 653: 8, 654: 8, 655: 8, 658: 6, 660: 8, 669: 3, 671: 8, 672: 8, 680: 8, 701: 8, 704: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 736: 8, 737: 8, 746: 5, 760: 8, 764: 8, 766: 8, 770: 8, 773: 8, 779: 8, 782: 8, 784: 8, 792: 8, 799: 8, 800: 8, 804: 8, 808: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 878: 8, 882: 8, 897: 8, 908: 8, 924: 8, 926: 3, 929: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 958: 8, 959: 8, 969: 4, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1082: 8, 1083: 8, 1098: 8, 1100: 8},
# based on 9ae7821dc4e92455|2019-07-01--16-42-55
{168: 8, 257: 5, 258: 8, 264: 8, 268: 8, 270: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 291: 8, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 368: 8, 376: 3, 384: 8, 388: 4, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 515: 7, 516: 7, 517: 7, 518: 7, 520: 8, 528: 8, 532: 8, 542: 8, 544: 8, 557: 8, 559: 8, 560: 4, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 653: 8, 654: 8, 655: 8, 658: 6, 660: 8, 669: 3, 671: 8, 672: 8, 678: 8, 680: 8, 701: 8, 704: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 737: 8, 746: 5, 760: 8, 764: 8, 766: 8, 770: 8, 773: 8, 779: 8, 782: 8, 784: 8, 792: 8, 799: 8, 800: 8, 804: 8, 808: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 878: 8, 882: 8, 897: 8, 908: 8, 924: 8, 926: 3, 929: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 958: 8, 959: 8, 969: 4, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1082: 8, 1083: 8, 1098: 8, 1100: 8, 1216: 8, 1218: 8, 1220: 8, 1225: 8, 1235: 8, 1242: 8, 1246: 8, 1250: 8, 1251: 8, 1252: 8, 1258: 8, 1259: 8, 1260: 8, 1262: 8, 1284: 8, 1537: 8, 1538: 8, 1562: 8, 1568: 8, 1856: 8, 1858: 8, 1860: 8, 1865: 8, 1875: 8, 1882: 8, 1886: 8, 1890: 8, 1891: 8, 1892: 8, 1898: 8, 1899: 8, 1900: 8, 1902: 8, 2016: 8, 2018: 8, 2019: 8, 2020: 8, 2023: 8, 2024: 8, 2026: 8, 2027: 8, 2028: 8, 2031: 8},
],
CAR.PACIFICA_2019_HYBRID: [
{168: 8, 257: 5, 258: 8, 264: 8, 268: 8, 270: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 291: 8, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 368: 8, 376: 3, 384: 8, 388: 4, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 515: 7, 516: 7, 517: 7, 518: 7, 520: 8, 528: 8, 532: 8, 542: 8, 544: 8, 557: 8, 559: 8, 560: 8, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 653: 8, 654: 8, 655: 8, 660: 8, 669: 3, 671: 8, 672: 8, 680: 8, 701: 8, 703: 8, 704: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 736: 8, 737: 8, 746: 5, 752: 2, 754: 8, 760: 8, 764: 8, 766: 8, 770:8, 773: 8, 779: 8, 782: 8, 784: 8, 792: 8, 799: 8, 800: 8, 804: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 878: 8, 882: 8, 897: 8, 906: 8, 908: 8, 924: 8, 926: 3, 929: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 958: 8, 959: 8, 962: 8, 969: 4, 973: 8, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1082: 8, 1083: 8, 1098: 8, 1100: 8, 1538: 8},
{168: 8, 257: 5, 258: 8, 264: 8, 268: 8, 270: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 291: 8, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 368: 8, 376: 3, 384: 8, 388: 4, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 515: 7, 516: 7, 517: 7, 518: 7, 520: 8, 528: 8, 532: 8, 542: 8, 544: 8, 557: 8, 559: 8, 560: 8, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 653: 8, 654: 8, 655: 8, 658: 6, 660: 8, 669: 3, 671: 8, 672: 8, 680: 8, 701: 8, 703: 8, 704: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 736: 8, 737: 8, 746: 5, 752: 2, 754: 8, 760: 8, 764: 8, 766: 8, 770:8, 773: 8, 779: 8, 782: 8, 784: 8, 792: 8, 799: 8, 800: 8, 804: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 878: 8, 882: 8, 897: 8, 906: 8, 908: 8, 924: 8, 926: 3, 929: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 958: 8, 959: 8, 962: 8, 969: 4, 973: 8, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1082: 8, 1083: 8, 1098: 8, 1100: 8, 1538: 8},
# Based on 0607d2516fc2148f|2019-02-13--23-03-16
{
168: 8, 257: 5, 258: 8, 264: 8, 268: 8, 270: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 291: 8, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 368: 8, 376: 3, 384: 8, 388: 4, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 520: 8, 528: 8, 532: 8, 544: 8, 557: 8, 559: 8, 560: 8, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 653: 8, 654: 8, 655: 8, 658: 6, 660: 8, 669: 3, 671: 8, 672: 8, 678: 8, 680: 8, 701: 8, 703: 8, 704: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 737: 8, 746: 5, 752: 2, 754: 8, 760: 8, 764: 8, 766: 8, 770: 8, 773: 8, 779: 8, 782: 8, 784: 8, 792: 8, 799: 8, 800: 8, 804: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 878: 8, 882: 8, 897: 8, 906: 8, 908: 8, 924: 8, 926: 3, 929: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 958: 8, 959: 8, 962: 8, 969: 4, 973: 8, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1082: 8, 1083: 8, 1098: 8, 1100: 8, 1537: 8
@ -46,12 +47,12 @@ FINGERPRINTS = {
# JEEP GRAND CHEROKEE V6 2018
{55: 8, 168: 8, 181: 8, 256: 4, 257: 5, 258: 8, 264: 8, 268: 8, 272: 6, 273: 6, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 292: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 352: 8, 362: 8, 368: 8, 376: 3, 384: 8, 388: 4, 416: 7, 448: 6, 456: 4, 464: 8, 500: 8, 501: 8, 512: 8, 514: 8, 520: 8, 532: 8, 544: 8, 557: 8, 559: 8, 560: 4, 564: 4, 571: 3, 579: 8, 584: 8, 608: 8, 618: 8, 624: 8, 625: 8, 632: 8, 639: 8, 656: 4, 658: 6, 660: 8, 671: 8, 672: 8, 676: 8, 678: 8, 680: 8, 683: 8, 684: 8, 703: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 737: 8, 738: 8, 746: 5, 752: 2, 754: 8, 760: 8, 761: 8, 764: 8, 766: 8, 773: 8, 776: 8, 779: 8, 782: 8, 783: 8, 784: 8, 785: 8, 788: 3, 792: 8, 799: 8, 800: 8, 804: 8, 806: 2, 808: 8, 810: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 831: 6, 832: 8, 838: 2, 844: 5, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 882: 8, 897: 8, 906: 8, 924: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 956: 8, 968: 8, 969: 4, 970: 8, 973: 8, 974: 5, 976: 8, 977: 4, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1062: 8, 1098: 8, 1100: 8},
# Jeep Grand Cherokee 2017 Trailhawk
{257: 5, 258: 8, 264: 8, 268: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 292: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 352: 8, 362: 8, 368: 8, 376: 3, 384: 8, 388: 4, 416: 7, 448: 6, 456: 4, 464: 8, 500: 8, 501: 8, 512: 8, 514: 8, 520: 8, 532: 8, 544: 8, 557: 8, 559: 8, 560: 4, 564: 4, 571: 3, 584: 8, 608: 8, 618: 8, 624: 8, 625: 8, 632: 8, 639: 8, 660: 8, 671: 8, 672: 8, 680: 8, 684: 8, 703: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 736: 8, 737: 8, 746: 5, 752: 2, 760: 8, 761: 8, 764: 8, 766: 8, 773: 8, 776: 8, 779: 8, 783: 8, 784: 8, 792: 8, 799: 8, 800: 8, 804: 8, 806: 2, 808: 8, 810: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 831: 6, 832: 8, 838: 2, 844: 5, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 882: 8, 897: 8, 924: 3, 937: 8, 947: 8, 948: 8, 969: 4, 974: 5, 977: 4, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1062: 8, 1098: 8, 1100: 8},
{257: 5, 258: 8, 264: 8, 268: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 292: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 352: 8, 362: 8, 368: 8, 376: 3, 384: 8, 388: 4, 416: 7, 448: 6, 456: 4, 464: 8, 500: 8, 501: 8, 512: 8, 514: 8, 520: 8, 532: 8, 544: 8, 557: 8, 559: 8, 560: 4, 564: 4, 571: 3, 584: 8, 608: 8, 618: 8, 624: 8, 625: 8, 632: 8, 639: 8, 658: 6, 660: 8, 671: 8, 672: 8, 680: 8, 684: 8, 703: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 736: 8, 737: 8, 746: 5, 752: 2, 760: 8, 761: 8, 764: 8, 766: 8, 773: 8, 776: 8, 779: 8, 783: 8, 784: 8, 792: 8, 799: 8, 800: 8, 804: 8, 806: 2, 808: 8, 810: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 831: 6, 832: 8, 838: 2, 844: 5, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 882: 8, 897: 8, 924: 3, 937: 8, 947: 8, 948: 8, 969: 4, 974: 5, 977: 4, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1062: 8, 1098: 8, 1100: 8},
],
CAR.JEEP_CHEROKEE_2019: [
# Jeep Grand Cherokee 2019 from Switzerland
# 530: 8 is so far only in this Jeep.
{55: 8, 181: 8, 256: 4, 257: 5, 258: 8, 264: 8, 268: 8, 272: 6, 273: 6, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 292: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 352: 8, 362: 8, 368: 8, 376: 3, 384: 8, 388: 4, 416: 7, 448: 6, 456: 4, 464: 8, 500: 8, 501: 8, 512: 8, 514: 8, 520: 8, 530: 8, 532: 8, 544: 8, 557: 8, 559: 8, 560: 8, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 618: 8, 624: 8, 625: 8, 632: 8, 639: 8, 660: 8, 671: 8, 672: 8, 676: 8, 680: 8, 683: 8, 684: 8, 703: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 736: 8, 737: 8, 738: 8, 746: 5, 752: 2, 754: 8, 760: 8, 761: 8, 764: 8, 773: 8, 776: 8, 779: 8, 782: 8, 783: 8, 784: 8, 792: 8, 799: 8, 804: 8, 806: 2, 808: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 831: 6, 832: 8, 838: 2, 844: 5, 848: 8, 853: 8, 856: 4, 860: 6, 882: 8, 897: 8, 906: 8, 924: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 968: 8, 969: 4, 970: 8, 973: 8, 974: 5, 977: 4, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1062: 8, 1098: 8, 1100: 8},
{55: 8, 181: 8, 256: 4, 257: 5, 258: 8, 264: 8, 268: 8, 272: 6, 273: 6, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 292: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 352: 8, 362: 8, 368: 8, 376: 3, 384: 8, 388: 4, 416: 7, 448: 6, 456: 4, 464: 8, 500: 8, 501: 8, 512: 8, 514: 8, 520: 8, 530: 8, 532: 8, 544: 8, 557: 8, 559: 8, 560: 8, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 618: 8, 624: 8, 625: 8, 632: 8, 639: 8, 658: 6, 660: 8, 671: 8, 672: 8, 676: 8, 680: 8, 683: 8, 684: 8, 703: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 736: 8, 737: 8, 738: 8, 746: 5, 752: 2, 754: 8, 760: 8, 761: 8, 764: 8, 773: 8, 776: 8, 779: 8, 782: 8, 783: 8, 784: 8, 792: 8, 799: 8, 804: 8, 806: 2, 808: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 831: 6, 832: 8, 838: 2, 844: 5, 848: 8, 853: 8, 856: 4, 860: 6, 882: 8, 897: 8, 906: 8, 924: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 968: 8, 969: 4, 970: 8, 973: 8, 974: 5, 977: 4, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1062: 8, 1098: 8, 1100: 8},
],
}
@ -85,10 +86,5 @@ class ECU:
ECU_FINGERPRINT = {
ECU.CAM: 0x2d9, # steer torque cmd
ECU.CAM: [0x292], # lkas cmd
}
def check_ecu_msgs(fingerprint, ecu):
# return True if fingerprint contains messages normally sent by a given ecu
return ECU_FINGERPRINT[ecu] in fingerprint

View File

@ -7,7 +7,7 @@ from selfdrive.can.packer import CANPacker
MAX_STEER_DELTA = 1
TOGGLE_DEBUG = False
class CarController(object):
class CarController():
def __init__(self, dbc_name, enable_camera, vehicle_model):
self.packer = CANPacker(dbc_name)
self.enable_camera = enable_camera
@ -48,7 +48,7 @@ class CarController(object):
if (frame % 100) == 0:
can_sends.append(make_can_msg(973, '\x00\x00\x00\x00\x00\x00\x00\x00', 0, False))
can_sends.append(make_can_msg(973, b'\x00\x00\x00\x00\x00\x00\x00\x00', 0, False))
#can_sends.append(make_can_msg(984, '\x00\x00\x00\x00\x80\x45\x60\x30', 0, False))
if (frame % 100) == 0 or (self.enabled_last != enabled) or (self.main_on_last != CS.main_on) or \
@ -56,29 +56,29 @@ class CarController(object):
can_sends.append(create_lkas_ui(self.packer, CS.main_on, enabled, steer_alert))
if (frame % 200) == 0:
can_sends.append(make_can_msg(1875, '\x80\xb0\x55\x55\x78\x90\x00\x00', 1, False))
can_sends.append(make_can_msg(1875, b'\x80\xb0\x55\x55\x78\x90\x00\x00', 1, False))
if (frame % 10) == 0:
can_sends.append(make_can_msg(1648, '\x00\x00\x00\x40\x00\x00\x50\x00', 1, False))
can_sends.append(make_can_msg(1649, '\x10\x10\xf1\x70\x04\x00\x00\x00', 1, False))
can_sends.append(make_can_msg(1648, b'\x00\x00\x00\x40\x00\x00\x50\x00', 1, False))
can_sends.append(make_can_msg(1649, b'\x10\x10\xf1\x70\x04\x00\x00\x00', 1, False))
can_sends.append(make_can_msg(1664, '\x00\x00\x03\xe8\x00\x01\xa9\xb2', 1, False))
can_sends.append(make_can_msg(1674, '\x08\x00\x00\xff\x0c\xfb\x6a\x08', 1, False))
can_sends.append(make_can_msg(1675, '\x00\x00\x3b\x60\x37\x00\x00\x00', 1, False))
can_sends.append(make_can_msg(1690, '\x70\x00\x00\x55\x86\x1c\xe0\x00', 1, False))
can_sends.append(make_can_msg(1664, b'\x00\x00\x03\xe8\x00\x01\xa9\xb2', 1, False))
can_sends.append(make_can_msg(1674, b'\x08\x00\x00\xff\x0c\xfb\x6a\x08', 1, False))
can_sends.append(make_can_msg(1675, b'\x00\x00\x3b\x60\x37\x00\x00\x00', 1, False))
can_sends.append(make_can_msg(1690, b'\x70\x00\x00\x55\x86\x1c\xe0\x00', 1, False))
can_sends.append(make_can_msg(1910, '\x06\x4b\x06\x4b\x42\xd3\x11\x30', 1, False))
can_sends.append(make_can_msg(1911, '\x48\x53\x37\x54\x48\x53\x37\x54', 1, False))
can_sends.append(make_can_msg(1912, '\x31\x34\x47\x30\x38\x31\x43\x42', 1, False))
can_sends.append(make_can_msg(1913, '\x31\x34\x47\x30\x38\x32\x43\x42', 1, False))
can_sends.append(make_can_msg(1969, '\xf4\x40\x00\x00\x00\x00\x00\x00', 1, False))
can_sends.append(make_can_msg(1971, '\x0b\xc0\x00\x00\x00\x00\x00\x00', 1, False))
can_sends.append(make_can_msg(1910, b'\x06\x4b\x06\x4b\x42\xd3\x11\x30', 1, False))
can_sends.append(make_can_msg(1911, b'\x48\x53\x37\x54\x48\x53\x37\x54', 1, False))
can_sends.append(make_can_msg(1912, b'\x31\x34\x47\x30\x38\x31\x43\x42', 1, False))
can_sends.append(make_can_msg(1913, b'\x31\x34\x47\x30\x38\x32\x43\x42', 1, False))
can_sends.append(make_can_msg(1969, b'\xf4\x40\x00\x00\x00\x00\x00\x00', 1, False))
can_sends.append(make_can_msg(1971, b'\x0b\xc0\x00\x00\x00\x00\x00\x00', 1, False))
static_msgs = range(1653, 1658)
for addr in static_msgs:
cnt = (frame % 10) + 1
can_sends.append(make_can_msg(addr, chr(cnt<<4) + '\x00\x00\x00\x00\x00\x00\x00', 1, False))
can_sends.append(make_can_msg(addr, (cnt<<4).to_bytes(1, 'little') + b'\x00\x00\x00\x00\x00\x00\x00', 1, False))
self.enabled_last = enabled
self.main_on_last = CS.main_on

View File

@ -1,8 +1,8 @@
from selfdrive.can.parser import CANParser
from common.numpy_fast import mean
from selfdrive.config import Conversions as CV
from selfdrive.car.ford.values import DBC
from common.kalman.simple_kalman import KF1D
import numpy as np
WHEEL_RADIUS = 0.33
@ -32,7 +32,7 @@ def get_can_parser(CP):
return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 0)
class CarState(object):
class CarState():
def __init__(self, CP):
self.CP = CP
@ -62,7 +62,7 @@ class CarState(object):
self.v_wheel_fr = cp.vl["WheelSpeed_CG1"]['WhlRl_W_Meas'] * WHEEL_RADIUS
self.v_wheel_rl = cp.vl["WheelSpeed_CG1"]['WhlFr_W_Meas'] * WHEEL_RADIUS
self.v_wheel_rr = cp.vl["WheelSpeed_CG1"]['WhlFl_W_Meas'] * WHEEL_RADIUS
v_wheel = float(np.mean([self.v_wheel_fl, self.v_wheel_fr, self.v_wheel_rl, self.v_wheel_rr]))
v_wheel = mean([self.v_wheel_fl, self.v_wheel_fr, self.v_wheel_rl, self.v_wheel_rr])
# Kalman filter
if abs(v_wheel - self.v_ego) > 2.0: # Prevent large accelerations when car starts at non zero speed

View File

@ -1,15 +1,16 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from cereal import car
from selfdrive.swaglog import cloudlog
from selfdrive.config import Conversions as CV
from selfdrive.controls.lib.drive_helpers import EventTypes as ET, create_event
from selfdrive.controls.lib.vehicle_model import VehicleModel
from selfdrive.car.ford.carstate import CarState, get_can_parser
from selfdrive.car.ford.values import MAX_ANGLE
from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness
from selfdrive.car.ford.values import MAX_ANGLE, ECU, ECU_FINGERPRINT, FINGERPRINTS
from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, is_ecu_disconnected, gen_empty_fingerprint
from selfdrive.car.interfaces import CarInterfaceBase
class CarInterface(object):
class CarInterface(CarInterfaceBase):
def __init__(self, CP, CarController):
self.CP = CP
self.VM = VehicleModel(CP)
@ -33,18 +34,14 @@ class CarInterface(object):
return float(accel) / 3.0
@staticmethod
def calc_accel_override(a_ego, a_target, v_ego, v_target):
return 1.0
@staticmethod
def get_params(candidate, fingerprint, vin="", is_panda_black=False):
def get_params(candidate, fingerprint=gen_empty_fingerprint(), vin="", has_relay=False):
ret = car.CarParams.new_message()
ret.carName = "ford"
ret.carFingerprint = candidate
ret.carVin = vin
ret.isPandaBlack = is_panda_black
ret.isPandaBlack = has_relay
ret.safetyModel = car.CarParams.SafetyModel.ford
ret.dashcamOnly = True
@ -88,9 +85,9 @@ class CarInterface(object):
ret.brakeMaxBP = [5., 20.]
ret.brakeMaxV = [1., 0.8]
ret.enableCamera = not any(x for x in [970, 973, 984] if x in fingerprint) or is_panda_black
ret.enableCamera = is_ecu_disconnected(fingerprint[0], FINGERPRINTS, ECU_FINGERPRINT, candidate, ECU.CAM) or has_relay
ret.openpilotLongitudinalControl = False
cloudlog.warn("ECU Camera Simulated: %r", ret.enableCamera)
cloudlog.warning("ECU Camera Simulated: %r", ret.enableCamera)
ret.steerLimitAlert = False
ret.stoppingControl = False

View File

@ -1,32 +1,32 @@
#!/usr/bin/env python
import os
import numpy as np
from selfdrive.can.parser import CANParser
#!/usr/bin/env python3
from cereal import car
from selfdrive.can.parser import CANParser
from selfdrive.car.ford.values import DBC
from selfdrive.config import Conversions as CV
from selfdrive.car.interfaces import RadarInterfaceBase
RADAR_MSGS = range(0x500, 0x540)
RADAR_MSGS = list(range(0x500, 0x540))
def _create_radar_can_parser():
dbc_f = 'ford_fusion_2018_adas.dbc'
def _create_radar_can_parser(car_fingerprint):
dbc_f = DBC[car_fingerprint]['radar']
msg_n = len(RADAR_MSGS)
signals = list(zip(['X_Rel'] * msg_n + ['Angle'] * msg_n + ['V_Rel'] * msg_n,
RADAR_MSGS * 3,
[0] * msg_n + [0] * msg_n + [0] * msg_n))
checks = list(zip(RADAR_MSGS, [20]*msg_n))
return CANParser(os.path.splitext(dbc_f)[0], signals, checks, 1)
return CANParser(dbc_f, signals, checks, 1)
class RadarInterface(object):
class RadarInterface(RadarInterfaceBase):
def __init__(self, CP):
# radar
self.pts = {}
self.validCnt = {key: 0 for key in RADAR_MSGS}
self.track_id = 0
self.delay = 0.0 # Delay of radar
self.delay = 0 # Delay of radar
# Nidec
self.rcp = _create_radar_can_parser()
self.rcp = _create_radar_can_parser(CP.carFingerprint)
self.trigger_msg = 0x53f
self.updated_messages = set()
@ -44,7 +44,7 @@ class RadarInterface(object):
errors.append("canError")
ret.errors = errors
for ii in self.updated_messages:
for ii in sorted(self.updated_messages):
cpt = self.rcp.vl[ii]
if cpt['X_Rel'] > 0.00001:
@ -63,7 +63,7 @@ class RadarInterface(object):
self.pts[ii].trackId = self.track_id
self.track_id += 1
self.pts[ii].dRel = cpt['X_Rel'] # from front of car
self.pts[ii].yRel = cpt['X_Rel'] * cpt['Angle'] * np.pi / 180. # in car frame's y axis, left is positive
self.pts[ii].yRel = cpt['X_Rel'] * cpt['Angle'] * CV.DEG_TO_RAD # in car frame's y axis, left is positive
self.pts[ii].vRel = cpt['V_Rel']
self.pts[ii].aRel = float('nan')
self.pts[ii].yvRel = float('nan')
@ -72,6 +72,6 @@ class RadarInterface(object):
if ii in self.pts:
del self.pts[ii]
ret.points = self.pts.values()
ret.points = list(self.pts.values())
self.updated_messages.clear()
return ret

View File

@ -11,6 +11,13 @@ FINGERPRINTS = {
}],
}
class ECU:
CAM = 0
ECU_FINGERPRINT = {
ECU.CAM: [970, 973, 984]
}
DBC = {
CAR.FUSION: dbc_dict('ford_fusion_2018_pt', 'ford_fusion_2018_adas'),
}

View File

@ -68,7 +68,7 @@ def process_hud_alert(hud_alert):
steer = 1
return steer
class CarController(object):
class CarController():
def __init__(self, canbus, car_fingerprint):
self.pedal_steady = 0.
self.start_time = 0.

View File

@ -1,5 +1,5 @@
import numpy as np
from cereal import car
from common.numpy_fast import mean
from common.kalman.simple_kalman import KF1D
from selfdrive.config import Conversions as CV
from selfdrive.can.parser import CANParser
@ -50,7 +50,7 @@ def get_powertrain_can_parser(CP, canbus):
return CANParser(DBC[CP.carFingerprint]['pt'], signals, [], canbus.powertrain)
class CarState(object):
class CarState():
def __init__(self, CP, canbus):
self.CP = CP
# initialize can parser
@ -78,7 +78,7 @@ class CarState(object):
self.v_wheel_fr = pt_cp.vl["EBCMWheelSpdFront"]['FRWheelSpd'] * CV.KPH_TO_MS
self.v_wheel_rl = pt_cp.vl["EBCMWheelSpdRear"]['RLWheelSpd'] * CV.KPH_TO_MS
self.v_wheel_rr = pt_cp.vl["EBCMWheelSpdRear"]['RRWheelSpd'] * CV.KPH_TO_MS
v_wheel = float(np.mean([self.v_wheel_fl, self.v_wheel_fr, self.v_wheel_rl, self.v_wheel_rr]))
v_wheel = mean([self.v_wheel_fl, self.v_wheel_fr, self.v_wheel_rl, self.v_wheel_rr])
if abs(v_wheel - self.v_ego) > 2.0: # Prevent large accelerations when car starts at non zero speed
self.v_ego_kf.x = [[v_wheel], [0.0]]

View File

@ -24,7 +24,7 @@ def create_steering_control_ct6(packer, canbus, apply_steer, v_ego, idx, enabled
dat = packer.make_can_msg("ASCMLKASteeringCmd", 0, values)[2]
# the checksum logic is weird
values['LKASteeringCmdChecksum'] = (0x2a +
sum([ord(i) for i in dat][:4]) +
sum(dat[:4]) +
values['LKASMode']) & 0x3ff
# pack again with checksum
dat = packer.make_can_msg("ASCMLKASteeringCmd", 0, values)[2]
@ -36,7 +36,7 @@ def create_steering_control_ct6(packer, canbus, apply_steer, v_ego, idx, enabled
def create_adas_keepalive(bus):
dat = "\x00\x00\x00\x00\x00\x00\x00"
dat = b"\x00\x00\x00\x00\x00\x00\x00"
return [[0x409, 0, dat, bus], [0x40a, 0, dat, bus]]
def create_gas_regen_command(packer, bus, throttle, idx, acc_engaged, at_full_stop):
@ -52,9 +52,9 @@ def create_gas_regen_command(packer, bus, throttle, idx, acc_engaged, at_full_st
}
dat = packer.make_can_msg("ASCMGasRegenCmd", bus, values)[2]
values["GasRegenChecksum"] = (((0xff - ord(dat[1])) & 0xff) << 16) | \
(((0xff - ord(dat[2])) & 0xff) << 8) | \
((0x100 - ord(dat[3]) - idx) & 0xff)
values["GasRegenChecksum"] = (((0xff -dat[1]) & 0xff) << 16) | \
(((0xff - dat[2]) & 0xff) << 8) | \
((0x100 - dat[3] - idx) & 0xff)
return packer.make_can_msg("ASCMGasRegenCmd", bus, values)
@ -106,13 +106,13 @@ def create_adas_time_status(bus, tt, idx):
chksum = 0x1000 - dat[0] - dat[1] - dat[2] - dat[3]
chksum = chksum & 0xfff
dat += [0x40 + (chksum >> 8), chksum & 0xff, 0x12]
return [0xa1, 0, "".join(map(chr, dat)), bus]
return [0xa1, 0, bytes(dat), bus]
def create_adas_steering_status(bus, idx):
dat = [idx << 6, 0xf0, 0x20, 0, 0, 0]
chksum = 0x60 + sum(dat)
dat += [chksum >> 8, chksum & 0xff]
return [0x306, 0, "".join(map(chr, dat)), bus]
return [0x306, 0, bytes(dat), bus]
def create_adas_accelerometer_speed_status(bus, speed_ms, idx):
spd = int(speed_ms * 16) & 0xfff
@ -125,24 +125,24 @@ def create_adas_accelerometer_speed_status(bus, speed_ms, idx):
dat = [0x08, spd >> 4, ((spd & 0xf) << 4) | (accel >> 8), accel & 0xff, 0]
chksum = 0x62 + far_range_mode + (idx << 2) + dat[0] + dat[1] + dat[2] + dat[3] + dat[4]
dat += [(idx << 5) + (far_range_mode << 4) + (near_range_mode << 3) + (chksum >> 8), chksum & 0xff]
return [0x308, 0, "".join(map(chr, dat)), bus]
return [0x308, 0, bytes(dat), bus]
def create_adas_headlights_status(bus):
return [0x310, 0, "\x42\x04", bus]
return [0x310, 0, b"\x42\x04", bus]
def create_lka_icon_command(bus, active, critical, steer):
if active and steer == 1:
if critical:
dat = "\x50\xc0\x14"
dat = b"\x50\xc0\x14"
else:
dat = "\x50\x40\x18"
dat = b"\x50\x40\x18"
elif active:
if critical:
dat = "\x40\xc0\x14"
dat = b"\x40\xc0\x14"
else:
dat = "\x40\x40\x18"
dat = b"\x40\x40\x18"
else:
dat = "\x00\x00\x00"
dat = b"\x00\x00\x00"
return [0x104c006c, 0, dat, bus]
# TODO: WIP

View File

@ -1,23 +1,24 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from cereal import car
from selfdrive.config import Conversions as CV
from selfdrive.controls.lib.drive_helpers import create_event, EventTypes as ET
from selfdrive.controls.lib.vehicle_model import VehicleModel
from selfdrive.car.gm.values import DBC, CAR, STOCK_CONTROL_MSGS, \
SUPERCRUISE_CARS, AccState
from selfdrive.car.gm.values import DBC, CAR, ECU, ECU_FINGERPRINT, \
SUPERCRUISE_CARS, AccState, FINGERPRINTS
from selfdrive.car.gm.carstate import CarState, CruiseButtons, get_powertrain_can_parser
from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness
from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, is_ecu_disconnected, gen_empty_fingerprint
from selfdrive.car.interfaces import CarInterfaceBase
ButtonType = car.CarState.ButtonEvent.Type
class CanBus(object):
class CanBus(CarInterfaceBase):
def __init__(self):
self.powertrain = 0
self.obstacle = 1
self.chassis = 2
self.sw_gmlan = 3
class CarInterface(object):
class CarInterface(CarInterfaceBase):
def __init__(self, CP, CarController):
self.CP = CP
@ -42,24 +43,22 @@ class CarInterface(object):
return float(accel) / 4.0
@staticmethod
def calc_accel_override(a_ego, a_target, v_ego, v_target):
return 1.0
@staticmethod
def get_params(candidate, fingerprint, vin="", is_panda_black=False):
def get_params(candidate, fingerprint=gen_empty_fingerprint(), vin="", has_relay=False):
ret = car.CarParams.new_message()
ret.carName = "gm"
ret.carFingerprint = candidate
ret.carVin = vin
ret.isPandaBlack = is_panda_black
ret.isPandaBlack = has_relay
ret.enableCruise = False
# 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).
ret.enableCamera = not any(x for x in STOCK_CONTROL_MSGS[candidate] if x in fingerprint) or is_panda_black
ret.enableCamera = is_ecu_disconnected(fingerprint[0], FINGERPRINTS, ECU_FINGERPRINT, candidate, ECU.CAM) or \
has_relay or \
candidate == CAR.CADILLAC_CT6
ret.openpilotLongitudinalControl = ret.enableCamera
tire_stiffness_factor = 0.444 # not optimized yet
ret.safetyModelPassive = car.CarParams.SafetyModel.gmPassive

View File

@ -1,11 +1,13 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from __future__ import print_function
import math
import time
import numpy as np
from cereal import car
from selfdrive.can.parser import CANParser
from selfdrive.car.gm.interface import CanBus
from selfdrive.car.gm.values import DBC, CAR
from selfdrive.config import Conversions as CV
from selfdrive.car.interfaces import RadarInterfaceBase
RADAR_HEADER_MSG = 1120
SLOT_1_MSG = RADAR_HEADER_MSG + 1
@ -20,7 +22,7 @@ def create_radar_can_parser(canbus, car_fingerprint):
dbc_f = DBC[car_fingerprint]['radar']
if car_fingerprint in (CAR.VOLT, CAR.MALIBU, CAR.HOLDEN_ASTRA, CAR.ACADIA, CAR.CADILLAC_ATS):
# C1A-ARS3-A by Continental
radar_targets = range(SLOT_1_MSG, SLOT_1_MSG + NUM_SLOTS)
radar_targets = list(range(SLOT_1_MSG, SLOT_1_MSG + NUM_SLOTS))
signals = list(zip(['FLRRNumValidTargets',
'FLRRSnsrBlckd', 'FLRRYawRtPlsblityFlt',
'FLRRHWFltPrsntInt', 'FLRRAntTngFltPrsnt',
@ -40,15 +42,15 @@ def create_radar_can_parser(canbus, car_fingerprint):
else:
return None
class RadarInterface(object):
class RadarInterface(RadarInterfaceBase):
def __init__(self, CP):
# radar
self.pts = {}
self.delay = 0.0 # Delay of radar
self.delay = 0 # Delay of radar
canbus = CanBus()
print "Using %d as obstacle CAN bus ID" % canbus.obstacle
print("Using %d as obstacle CAN bus ID" % canbus.obstacle)
self.rcp = create_radar_can_parser(canbus, CP.carFingerprint)
self.trigger_msg = LAST_RADAR_MSG
@ -65,7 +67,6 @@ class RadarInterface(object):
if self.trigger_msg not in self.updated_messages:
return None
ret = car.RadarData.new_message()
header = self.rcp.vl[RADAR_HEADER_MSG]
fault = header['FLRRSnsrBlckd'] or header['FLRRSnstvFltPrsntInt'] or \
@ -101,16 +102,15 @@ class RadarInterface(object):
distance = cpt['TrkRange']
self.pts[targetId].dRel = distance # from front of car
# From driver's pov, left is positive
deg_to_rad = np.pi/180.
self.pts[targetId].yRel = math.sin(deg_to_rad * cpt['TrkAzimuth']) * distance
self.pts[targetId].yRel = math.sin(cpt['TrkAzimuth'] * CV.DEG_TO_RAD) * distance
self.pts[targetId].vRel = cpt['TrkRangeRate']
self.pts[targetId].aRel = float('nan')
self.pts[targetId].yvRel = float('nan')
for oldTarget in self.pts.keys():
for oldTarget in list(self.pts.keys()):
if not oldTarget in currentTargets:
del self.pts[oldTarget]
ret.points = self.pts.values()
ret.points = list(self.pts.values())
self.updated_messages.clear()
return ret

View File

@ -48,12 +48,12 @@ def parse_gear_shifter(can_gear):
FINGERPRINTS = {
# Astra BK MY17, ASCM unplugged
CAR.HOLDEN_ASTRA: [{
190: 8, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 8, 241: 6, 249: 8, 288: 5, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 381: 6, 386: 8, 388: 8, 393: 8, 398: 8, 401: 8, 413: 8, 417: 8, 419: 8, 422: 1, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 8, 455: 7, 456: 8, 458: 5, 479: 8, 481: 7, 485: 8, 489: 8, 497: 8, 499: 3, 500: 8, 501: 8, 508: 8, 528: 5, 532: 6, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 567: 5, 647: 5, 707: 8, 723: 8, 753: 5, 761: 7, 806: 1, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 961: 8, 969: 8, 977: 8, 979: 8, 985: 5, 1001: 8, 1009: 8, 1011: 6, 1017: 8, 1019: 3, 1020: 8, 1105: 6, 1217: 8, 1221: 5, 1225: 8, 1233: 8, 1249: 8, 1257: 6, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 8, 1280: 4, 1300: 8, 1328: 4, 1417: 8, 1906: 7, 1907: 7, 1908: 7, 1912: 7, 1919: 7,
190: 8, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 8, 241: 6, 249: 8, 288: 5, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 381: 6, 384: 4, 386: 8, 388: 8, 393: 8, 398: 8, 401: 8, 413: 8, 417: 8, 419: 8, 422: 1, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 8, 455: 7, 456: 8, 458: 5, 479: 8, 481: 7, 485: 8, 489: 8, 497: 8, 499: 3, 500: 8, 501: 8, 508: 8, 528: 5, 532: 6, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 567: 5, 647: 5, 707: 8, 715: 8, 723: 8, 753: 5, 761: 7, 806: 1, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 961: 8, 969: 8, 977: 8, 979: 8, 985: 5, 1001: 8, 1009: 8, 1011: 6, 1017: 8, 1019: 3, 1020: 8, 1105: 6, 1217: 8, 1221: 5, 1225: 8, 1233: 8, 1249: 8, 1257: 6, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 8, 1280: 4, 1300: 8, 1328: 4, 1417: 8, 1906: 7, 1907: 7, 1908: 7, 1912: 7, 1919: 7,
}],
CAR.VOLT: [
# Volt Premier w/ ACC 2017
{
170: 8, 171: 8, 189: 7, 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 2, 241: 6, 288: 5, 289: 8, 298: 8, 304: 1, 308: 4, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 381: 6, 386: 8, 388: 8, 389: 2, 390: 7, 417: 7, 419: 1, 426: 7, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 479: 3, 481: 7, 485: 8, 489: 8, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 508: 8, 528: 4, 532: 6, 546: 7, 550: 8, 554: 3, 558: 8, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 566: 5, 567: 3, 568: 1, 573: 1, 577: 8, 647: 3, 707: 8, 711: 6, 761: 7, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 961: 8, 969: 8, 977: 8, 979: 7, 988: 6, 989: 8, 995: 7, 1001: 8, 1005: 6, 1009: 8, 1017: 8, 1019: 2, 1020: 8, 1105: 6, 1187: 4, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1273: 3, 1275: 3, 1280: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1417: 8, 1601: 8, 1905: 7, 1906: 7, 1907: 7, 1910: 7, 1912: 7, 1922: 7, 1927: 7, 1928: 7, 2016: 8, 2020: 8, 2024: 8, 2028: 8
170: 8, 171: 8, 189: 7, 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 2, 241: 6, 288: 5, 289: 8, 298: 8, 304: 1, 308: 4, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 381: 6, 384: 4, 386: 8, 388: 8, 389: 2, 390: 7, 417: 7, 419: 1, 426: 7, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 479: 3, 481: 7, 485: 8, 489: 8, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 508: 8, 528: 4, 532: 6, 546: 7, 550: 8, 554: 3, 558: 8, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 566: 5, 567: 3, 568: 1, 573: 1, 577: 8, 647: 3, 707: 8, 711: 6, 715: 8, 761: 7, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 961: 8, 969: 8, 977: 8, 979: 7, 988: 6, 989: 8, 995: 7, 1001: 8, 1005: 6, 1009: 8, 1017: 8, 1019: 2, 1020: 8, 1105: 6, 1187: 4, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1273: 3, 1275: 3, 1280: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1417: 8, 1601: 8, 1905: 7, 1906: 7, 1907: 7, 1910: 7, 1912: 7, 1922: 7, 1927: 7, 1928: 7, 2016: 8, 2020: 8, 2024: 8, 2028: 8
},
# Volt Premier w/ ACC 2018
{
@ -86,14 +86,11 @@ FINGERPRINTS = {
STEER_THRESHOLD = 1.0
STOCK_CONTROL_MSGS = {
CAR.HOLDEN_ASTRA: [384, 715],
CAR.VOLT: [384, 715], # 384 = "ASCMLKASteeringCmd", 715 = "ASCMGasRegenCmd"
CAR.MALIBU: [384, 715], # 384 = "ASCMLKASteeringCmd", 715 = "ASCMGasRegenCmd"
CAR.ACADIA: [384, 715], # 384 = "ASCMLKASteeringCmd", 715 = "ASCMGasRegenCmd"
CAR.CADILLAC_ATS: [384, 715], # 384 = "ASCMLKASteeringCmd", 715 = "ASCMGasRegenCmd"
CAR.BUICK_REGAL: [384, 715], # 384 = "ASCMLKASteeringCmd", 715 = "ASCMGasRegenCmd"
CAR.CADILLAC_CT6: [], # CT6 does not require ASCMs to be disconnected
class ECU:
CAM = 0
ECU_FINGERPRINT = {
ECU.CAM: [384, 715] # 384 = "ASCMLKASteeringCmd", 715 = "ASCMGasRegenCmd"
}
DBC = {

View File

@ -73,7 +73,7 @@ HUDData = namedtuple("HUDData",
"lanes", "fcw", "acc_alert", "steer_required"])
class CarController(object):
class CarController():
def __init__(self, dbc_name):
self.braking = False
self.brake_steady = 0.

View File

@ -1,4 +1,5 @@
from cereal import car
from collections import defaultdict
from common.numpy_fast import interp
from common.kalman.simple_kalman import KF1D
from selfdrive.can.can_define import CANDefine
@ -178,11 +179,12 @@ def get_cam_can_parser(CP):
bus_cam = 1 if CP.carFingerprint in HONDA_BOSCH and not CP.isPandaBlack else 2
return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, bus_cam)
class CarState(object):
class CarState():
def __init__(self, CP):
self.CP = CP
self.can_define = CANDefine(DBC[CP.carFingerprint]['pt'])
self.shifter_values = self.can_define.dv["GEARBOX"]["GEAR_SHIFTER"]
self.steer_status_values = defaultdict(lambda: "UNKNOWN", self.can_define.dv["STEER_STATUS"]["STEER_STATUS"])
self.user_gas, self.user_gas_pressed = 0., 0
self.brake_switch_prev = 0
@ -224,7 +226,6 @@ class CarState(object):
self.prev_right_blinker_on = self.right_blinker_on
# ******************* parse out can *******************
if self.CP.carFingerprint in (CAR.ACCORD, CAR.ACCORD_15, CAR.ACCORDH, CAR.CIVIC_BOSCH, CAR.CRV_HYBRID): # TODO: find wheels moving bit in dbc
self.standstill = cp.vl["ENGINE_DATA"]['XMISSION_SPEED'] < 0.1
self.door_all_closed = not cp.vl["SCM_FEEDBACK"]['DRIVERS_DOOR_OPEN']
@ -237,11 +238,13 @@ class CarState(object):
cp.vl["DOORS_STATUS"]['DOOR_OPEN_RL'], cp.vl["DOORS_STATUS"]['DOOR_OPEN_RR']])
self.seatbelt = not cp.vl["SEATBELT_STATUS"]['SEATBELT_DRIVER_LAMP'] and cp.vl["SEATBELT_STATUS"]['SEATBELT_DRIVER_LATCHED']
# 2 = temporary; 3 = TBD; 4 = significant steering wheel torque; 5 = (permanent); 6 = temporary; 7 = (permanent)
# TODO: Use values from DBC to parse this field
self.steer_error = cp.vl["STEER_STATUS"]['STEER_STATUS'] not in [0, 2, 3, 4, 6]
self.steer_not_allowed = cp.vl["STEER_STATUS"]['STEER_STATUS'] not in [0, 4] # 4 can be caused by bump OR steering nudge from driver
self.steer_warning = cp.vl["STEER_STATUS"]['STEER_STATUS'] not in [0, 3, 4] # 3 is low speed lockout, not worth a warning
steer_status = self.steer_status_values[cp.vl["STEER_STATUS"]['STEER_STATUS']]
self.steer_error = 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']
# LOW_SPEED_LOCKOUT is not worth a warning
self.steer_warning = steer_status not in ['NORMAL', 'LOW_SPEED_LOCKOUT', 'NO_TORQUE_ALERT_2']
if self.CP.radarOffCan:
self.brake_error = 0
else:
@ -357,7 +360,7 @@ if __name__ == '__main__':
import zmq
context = zmq.Context()
class CarParams(object):
class CarParams():
def __init__(self):
self.carFingerprint = "HONDA CIVIC 2016 TOURING"
self.enableGasInterceptor = 0

View File

@ -6,7 +6,6 @@ from selfdrive.car.honda.values import CAR, HONDA_BOSCH
def can_cksum(mm):
s = 0
for c in mm:
c = ord(c)
s += (c>>4)
s += c & 0xF
s = 8-s
@ -15,19 +14,19 @@ def can_cksum(mm):
def fix(msg, addr):
msg2 = msg[0:-1] + chr(ord(msg[-1]) | can_cksum(struct.pack("I", addr)+msg))
msg2 = msg[0:-1] + (msg[-1] | can_cksum(struct.pack("I", addr)+msg)).to_bytes(1, 'little')
return msg2
def get_pt_bus(car_fingerprint, is_panda_black):
return 1 if car_fingerprint in HONDA_BOSCH and is_panda_black else 0
def get_pt_bus(car_fingerprint, has_relay):
return 1 if car_fingerprint in HONDA_BOSCH and has_relay else 0
def get_lkas_cmd_bus(car_fingerprint, is_panda_black):
return 2 if car_fingerprint in HONDA_BOSCH and not is_panda_black else 0
def get_lkas_cmd_bus(car_fingerprint, has_relay):
return 2 if car_fingerprint in HONDA_BOSCH and not has_relay else 0
def create_brake_command(packer, apply_brake, pump_on, pcm_override, pcm_cancel_cmd, fcw, idx, car_fingerprint, is_panda_black):
def create_brake_command(packer, apply_brake, pump_on, pcm_override, pcm_cancel_cmd, fcw, idx, car_fingerprint, has_relay):
# TODO: do we loose pressure if we keep pump off for long?
brakelights = apply_brake > 0
brake_rq = apply_brake > 0
@ -49,23 +48,23 @@ def create_brake_command(packer, apply_brake, pump_on, pcm_override, pcm_cancel_
"AEB_REQ_2": 0,
"AEB_STATUS": 0,
}
bus = get_pt_bus(car_fingerprint, is_panda_black)
bus = get_pt_bus(car_fingerprint, has_relay)
return packer.make_can_msg("BRAKE_COMMAND", bus, values, idx)
def create_steering_control(packer, apply_steer, lkas_active, car_fingerprint, idx, is_panda_black):
def create_steering_control(packer, apply_steer, lkas_active, car_fingerprint, idx, has_relay):
values = {
"STEER_TORQUE": apply_steer if lkas_active else 0,
"STEER_TORQUE_REQUEST": lkas_active,
}
bus = get_lkas_cmd_bus(car_fingerprint, is_panda_black)
bus = get_lkas_cmd_bus(car_fingerprint, has_relay)
return packer.make_can_msg("STEERING_CONTROL", bus, values, idx)
def create_ui_commands(packer, pcm_speed, hud, car_fingerprint, is_metric, idx, is_panda_black):
def create_ui_commands(packer, pcm_speed, hud, car_fingerprint, is_metric, idx, has_relay):
commands = []
bus_pt = get_pt_bus(car_fingerprint, is_panda_black)
bus_lkas = get_lkas_cmd_bus(car_fingerprint, is_panda_black)
bus_pt = get_pt_bus(car_fingerprint, has_relay)
bus_lkas = get_lkas_cmd_bus(car_fingerprint, has_relay)
if car_fingerprint not in HONDA_BOSCH:
acc_hud_values = {
@ -101,10 +100,10 @@ def create_ui_commands(packer, pcm_speed, hud, car_fingerprint, is_metric, idx,
return commands
def spam_buttons_command(packer, button_val, idx, car_fingerprint, is_panda_black):
def spam_buttons_command(packer, button_val, idx, car_fingerprint, has_relay):
values = {
'CRUISE_BUTTONS': button_val,
'CRUISE_SETTING': 0,
}
bus = get_pt_bus(car_fingerprint, is_panda_black)
bus = get_pt_bus(car_fingerprint, has_relay)
return packer.make_can_msg("SCM_BUTTONS", bus, values, idx)

View File

@ -1,5 +1,4 @@
#!/usr/bin/env python
import os
#!/usr/bin/env python3
import numpy as np
from cereal import car
from common.numpy_fast import clip, interp
@ -9,11 +8,12 @@ from selfdrive.config import Conversions as CV
from selfdrive.controls.lib.drive_helpers import create_event, EventTypes as ET, get_events
from selfdrive.controls.lib.vehicle_model import VehicleModel
from selfdrive.car.honda.carstate import CarState, get_can_parser, get_cam_can_parser
from selfdrive.car.honda.values import CruiseButtons, CAR, HONDA_BOSCH, VISUAL_HUD, CAMERA_MSGS
from selfdrive.car import STD_CARGO_KG, CivicParams, scale_rot_inertia, scale_tire_stiffness
from selfdrive.controls.lib.planner import _A_CRUISE_MAX_V_FOLLOWING
from selfdrive.car.honda.values import CruiseButtons, CAR, HONDA_BOSCH, VISUAL_HUD, ECU, ECU_FINGERPRINT, FINGERPRINTS
from selfdrive.car import STD_CARGO_KG, CivicParams, scale_rot_inertia, scale_tire_stiffness, is_ecu_disconnected, gen_empty_fingerprint
from selfdrive.controls.lib.planner import _A_CRUISE_MAX_V
from selfdrive.car.interfaces import CarInterfaceBase
A_ACC_MAX = max(_A_CRUISE_MAX_V_FOLLOWING)
A_ACC_MAX = max(_A_CRUISE_MAX_V)
ButtonType = car.CarState.ButtonEvent.Type
GearShifter = car.CarState.GearShifter
@ -72,7 +72,7 @@ def get_compute_gb_acura():
return _compute_gb_acura
class CarInterface(object):
class CarInterface(CarInterfaceBase):
def __init__(self, CP, CarController):
self.CP = CP
@ -131,27 +131,28 @@ class CarInterface(object):
return float(max(max_accel, a_target / A_ACC_MAX)) * min(speedLimiter, accelLimiter)
@staticmethod
def get_params(candidate, fingerprint, vin="", is_panda_black=False):
def get_params(candidate, fingerprint=gen_empty_fingerprint(), vin="", has_relay=False):
ret = car.CarParams.new_message()
ret.carName = "honda"
ret.carFingerprint = candidate
ret.carVin = vin
ret.isPandaBlack = is_panda_black
ret.isPandaBlack = has_relay
if candidate in HONDA_BOSCH:
ret.safetyModel = car.CarParams.SafetyModel.hondaBosch
ret.enableCamera = True
rdr_bus = 0 if has_relay else 2
ret.enableCamera = is_ecu_disconnected(fingerprint[rdr_bus], FINGERPRINTS, ECU_FINGERPRINT, candidate, ECU.CAM) or has_relay
ret.radarOffCan = True
ret.openpilotLongitudinalControl = False
else:
ret.safetyModel = car.CarParams.SafetyModel.honda
ret.enableCamera = not any(x for x in CAMERA_MSGS if x in fingerprint) or is_panda_black
ret.enableGasInterceptor = 0x201 in fingerprint
ret.enableCamera = is_ecu_disconnected(fingerprint[0], FINGERPRINTS, ECU_FINGERPRINT, candidate, ECU.CAM) or has_relay
ret.enableGasInterceptor = 0x201 in fingerprint[0]
ret.openpilotLongitudinalControl = ret.enableCamera
cloudlog.warn("ECU Camera Simulated: %r", ret.enableCamera)
cloudlog.warn("ECU Gas Interceptor: %r", ret.enableGasInterceptor)
cloudlog.warning("ECU Camera Simulated: %r", ret.enableCamera)
cloudlog.warning("ECU Gas Interceptor: %r", ret.enableGasInterceptor)
ret.enableCruise = not ret.enableGasInterceptor
@ -172,12 +173,8 @@ class CarInterface(object):
ret.centerToFront = CivicParams.CENTER_TO_FRONT
ret.steerRatio = 15.38 # 10.93 is end-to-end spec
tire_stiffness_factor = 1.
# Civic at comma has modified steering FW, so different tuning for the Neo in that car
is_fw_modified = os.getenv("DONGLE_ID") in ['5b7c365c50084530']
if is_fw_modified:
ret.lateralTuning.pid.kf = 0.00004
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.4], [0.12]] if is_fw_modified else [[0.8], [0.24]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]]
ret.longitudinalTuning.kpBP = [0., 5., 35.]
ret.longitudinalTuning.kpV = [3.6, 2.4, 1.5]
ret.longitudinalTuning.kiBP = [0., 35.]

View File

@ -1,23 +1,25 @@
#!/usr/bin/env python
#!/usr/bin/env python3
import os
import time
from cereal import car
from selfdrive.can.parser import CANParser
from common.realtime import DT_RDR
from selfdrive.car.interfaces import RadarInterfaceBase
def _create_nidec_can_parser():
dbc_f = 'acura_ilx_2016_nidec.dbc'
radar_messages = [0x400] + range(0x430, 0x43A) + range(0x440, 0x446)
radar_messages = [0x400] + list(range(0x430, 0x43A)) + list(range(0x440, 0x446))
signals = list(zip(['RADAR_STATE'] +
['LONG_DIST'] * 16 + ['NEW_TRACK'] * 16 + ['LAT_DIST'] * 16 +
['REL_SPEED'] * 16,
[0x400] + radar_messages[1:] * 4,
[0] + [255] * 16 + [1] * 16 + [0] * 16 + [0] * 16))
checks = list(zip([0x445], [20]))
return CANParser(os.path.splitext(dbc_f)[0], signals, checks, 1)
fn = os.path.splitext(dbc_f)[0].encode('utf8')
return CANParser(fn, signals, checks, 1)
class RadarInterface(object):
class RadarInterface(RadarInterfaceBase):
def __init__(self, CP):
# radar
self.pts = {}
@ -26,7 +28,7 @@ class RadarInterface(object):
self.radar_wrong_config = False
self.radar_off_can = CP.radarOffCan
self.delay = 0.1 # Delay of radar
self.delay = int(0.1 / DT_RDR) # 0.1s delay of radar
# Nidec
self.rcp = _create_nidec_can_parser()
@ -55,7 +57,7 @@ class RadarInterface(object):
def _update(self, updated_messages):
ret = car.RadarData.new_message()
for ii in updated_messages:
for ii in sorted(updated_messages):
cpt = self.rcp.vl[ii]
if ii == 0x400:
# check for radar faults
@ -85,6 +87,6 @@ class RadarInterface(object):
errors.append("wrongConfig")
ret.errors = errors
ret.points = self.pts.values()
ret.points = list(self.pts.values())
return ret

View File

@ -30,6 +30,9 @@ VISUAL_HUD = {
VisualAlert.seatbeltUnbuckled: AH.SEATBELT,
VisualAlert.speedTooHigh: AH.SPEED_TOO_HIGH}
class ECU:
CAM = 0
class CAR:
ACCORD = "HONDA ACCORD 2018 SPORT 2T"
ACCORD_15 = "HONDA ACCORD 2018 LX 1.5T"
@ -116,7 +119,7 @@ FINGERPRINTS = {
},
# 2019 Ridgeline
{
57: 3, 145: 8, 229: 4, 308: 5, 316: 8, 339: 7, 342: 6, 344: 8, 380: 8, 392: 6, 399: 7, 419: 8, 420: 8, 422:8, 425: 8, 426: 8, 427: 3, 432: 7, 464: 8, 476: 4, 490: 8, 545: 5, 546: 3, 597: 8, 660: 8, 773: 7, 777: 8, 795: 8, 800: 8, 804: 8, 808: 8, 819: 7, 821: 5, 871: 8, 882: 2, 884: 7, 892: 8, 923: 2, 929: 8, 963: 8, 965: 8, 966: 8, 967: 8, 983: 8, 985: 3, 1027: 5, 1029: 8, 1036: 8, 1039: 8, 1064: 7, 1088: 8, 1089: 8, 1092: 1, 1108: 8, 1125: 8, 1296: 8, 1365: 5, 424: 5, 1613: 5, 1616: 5, 1618: 5, 1623: 5, 1668: 5
57: 3, 145: 8, 228: 5, 229: 4, 308: 5, 316: 8, 339: 7, 342: 6, 344: 8, 380: 8, 392: 6, 399: 7, 419: 8, 420: 8, 422:8, 425: 8, 426: 8, 427: 3, 432: 7, 464: 8, 476: 4, 490: 8, 545: 5, 546: 3, 597: 8, 660: 8, 773: 7, 777: 8, 795: 8, 800: 8, 804: 8, 808: 8, 819: 7, 821: 5, 871: 8, 882: 2, 884: 7, 892: 8, 923: 2, 929: 8, 963: 8, 965: 8, 966: 8, 967: 8, 983: 8, 985: 3, 1027: 5, 1029: 8, 1036: 8, 1039: 8, 1064: 7, 1088: 8, 1089: 8, 1092: 1, 1108: 8, 1125: 8, 1296: 8, 1365: 5, 424: 5, 1613: 5, 1616: 5, 1618: 5, 1623: 5, 1668: 5
}]
}
@ -185,7 +188,8 @@ SPEED_FACTOR = {
# msgs sent for steering controller by camera module on can 0.
# those messages are mutually exclusive on CRV and non-CRV cars
CAMERA_MSGS = [0xe4, 0x194]
ECU_FINGERPRINT = {
ECU.CAM: [0xE4, 0x194], # steer torque cmd
}
# TODO: get these from dbc file
HONDA_BOSCH = [CAR.ACCORD, CAR.ACCORD_15, CAR.ACCORDH, CAR.CIVIC_BOSCH, CAR.CRV_5G, CAR.CRV_HYBRID]

View File

@ -16,7 +16,7 @@ class SteerLimitParams:
STEER_DRIVER_MULTIPLIER = 2
STEER_DRIVER_FACTOR = 1
class CarController(object):
class CarController():
def __init__(self, dbc_name, car_fingerprint):
self.apply_steer_last = 0
self.car_fingerprint = car_fingerprint

View File

@ -1,8 +1,10 @@
from cereal import car
from selfdrive.car.hyundai.values import DBC, STEER_THRESHOLD
from selfdrive.can.parser import CANParser
from selfdrive.config import Conversions as CV
from common.kalman.simple_kalman import KF1D
GearShifter = car.CarState.GearShifter
def get_can_parser(CP):
@ -31,7 +33,7 @@ def get_can_parser(CP):
("CYL_PRES", "ESP12", 0),
("CF_Clu_CruiseSwState", "CLU11", 0),
("CF_Clu_CruiseSwMain" , "CLU11", 0),
("CF_Clu_CruiseSwMain", "CLU11", 0),
("CF_Clu_SldMainSW", "CLU11", 0),
("CF_Clu_ParityBit1", "CLU11", 0),
("CF_Clu_VanzDecimal" , "CLU11", 0),
@ -48,7 +50,7 @@ def get_can_parser(CP):
("CF_Clu_InhibitN", "CLU15", 0),
("CF_Clu_InhibitR", "CLU15", 0),
("CF_Lvr_Gear","LVR12",0),
("CF_Lvr_Gear", "LVR12",0),
("CUR_GR", "TCU12",0),
("ACCEnable", "TCS13", 0),
@ -122,7 +124,7 @@ def get_camera_parser(CP):
return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 2)
class CarState(object):
class CarState():
def __init__(self, CP):
self.CP = CP
@ -211,38 +213,38 @@ class CarState(object):
# Gear Selecton - This is not compatible with all Kia/Hyundai's, But is the best way for those it is compatible with
gear = cp.vl["LVR12"]["CF_Lvr_Gear"]
if gear == 5:
self.gear_shifter = "drive"
self.gear_shifter = GearShifter.drive
elif gear == 6:
self.gear_shifter = "neutral"
self.gear_shifter = GearShifter.neutral
elif gear == 0:
self.gear_shifter = "park"
self.gear_shifter = GearShifter.park
elif gear == 7:
self.gear_shifter = "reverse"
self.gear_shifter = GearShifter.reverse
else:
self.gear_shifter = "unknown"
self.gear_shifter = GearShifter.unknown
# Gear Selection via Cluster - For those Kia/Hyundai which are not fully discovered, we can use the Cluster Indicator for Gear Selection, as this seems to be standard over all cars, but is not the preferred method.
if cp.vl["CLU15"]["CF_Clu_InhibitD"] == 1:
self.gear_shifter_cluster = "drive"
self.gear_shifter_cluster = GearShifter.drive
elif cp.vl["CLU15"]["CF_Clu_InhibitN"] == 1:
self.gear_shifter_cluster = "neutral"
self.gear_shifter_cluster = GearShifter.neutral
elif cp.vl["CLU15"]["CF_Clu_InhibitP"] == 1:
self.gear_shifter_cluster = "park"
self.gear_shifter_cluster = GearShifter.park
elif cp.vl["CLU15"]["CF_Clu_InhibitR"] == 1:
self.gear_shifter_cluster = "reverse"
self.gear_shifter_cluster = GearShifter.reverse
else:
self.gear_shifter_cluster = "unknown"
self.gear_shifter_cluster = GearShifter.unknown
# Gear Selecton via TCU12
gear2 = cp.vl["TCU12"]["CUR_GR"]
if gear2 == 0:
self.gear_tcu = "park"
self.gear_tcu = GearShifter.park
elif gear2 == 14:
self.gear_tcu = "reverse"
self.gear_tcu = GearShifter.reverse
elif gear2 > 0 and gear2 < 9: # unaware of anything over 8 currently
self.gear_tcu = "drive"
self.gear_tcu = GearShifter.drive
else:
self.gear_tcu = "unknown"
self.gear_tcu = GearShifter.unknown
# save the entire LKAS11 and CLU11
self.lkas11 = cp_cam.vl["LKAS11"]

View File

@ -34,15 +34,13 @@ def create_lkas11(packer, car_fingerprint, apply_steer, steer_req, cnt, enabled,
if car_fingerprint in CHECKSUM["crc8"]:
# CRC Checksum as seen on 2019 Hyundai Santa Fe
dat = dat[:6] + dat[7]
dat = dat[:6] + dat[7:8]
checksum = hyundai_checksum(dat)
elif car_fingerprint in CHECKSUM["6B"]:
# Checksum of first 6 Bytes, as seen on 2018 Kia Sorento
dat = [ord(i) for i in dat]
checksum = sum(dat[:6]) % 256
elif car_fingerprint in CHECKSUM["7B"]:
# Checksum of first 6 Bytes and last Byte as seen on 2018 Kia Stinger
dat = [ord(i) for i in dat]
checksum = (sum(dat[:6]) + dat[7]) % 256
values["CF_Lkas_Chksum"] = checksum
@ -50,15 +48,15 @@ def create_lkas11(packer, car_fingerprint, apply_steer, steer_req, cnt, enabled,
return packer.make_can_msg("LKAS11", 0, values)
def create_lkas12():
return make_can_msg(1342, "\x00\x00\x00\x00\x60\x05", 0)
return make_can_msg(1342, b"\x00\x00\x00\x00\x60\x05", 0)
def create_1191():
return make_can_msg(1191, "\x01\x00", 0)
return make_can_msg(1191, b"\x01\x00", 0)
def create_1156():
return make_can_msg(1156, "\x08\x20\xfe\x3f\x00\xe0\xfd\x3f", 0)
return make_can_msg(1156, b"\x08\x20\xfe\x3f\x00\xe0\xfd\x3f", 0)
def create_clu11(packer, clu11, button):
values = {

View File

@ -1,16 +1,17 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from cereal import car
from selfdrive.config import Conversions as CV
from selfdrive.controls.lib.drive_helpers import EventTypes as ET, create_event
from selfdrive.controls.lib.vehicle_model import VehicleModel
from selfdrive.car.hyundai.carstate import CarState, get_can_parser, get_camera_parser
from selfdrive.car.hyundai.values import CAMERA_MSGS, CAR, get_hud_alerts, FEATURES
from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness
from selfdrive.car.hyundai.values import ECU, ECU_FINGERPRINT, CAR, get_hud_alerts, FEATURES, FINGERPRINTS
from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, is_ecu_disconnected, gen_empty_fingerprint
from selfdrive.car.interfaces import CarInterfaceBase
GearShifter = car.CarState.GearShifter
ButtonType = car.CarState.ButtonEvent.Type
class CarInterface(object):
class CarInterface(CarInterfaceBase):
def __init__(self, CP, CarController):
self.CP = CP
self.VM = VehicleModel(CP)
@ -37,18 +38,14 @@ class CarInterface(object):
return float(accel) / 3.0
@staticmethod
def calc_accel_override(a_ego, a_target, v_ego, v_target):
return 1.0
@staticmethod
def get_params(candidate, fingerprint, vin="", is_panda_black=False):
def get_params(candidate, fingerprint=gen_empty_fingerprint(), vin="", has_relay=False):
ret = car.CarParams.new_message()
ret.carName = "hyundai"
ret.carFingerprint = candidate
ret.carVin = vin
ret.isPandaBlack = is_panda_black
ret.isPandaBlack = has_relay
ret.radarOffCan = True
ret.safetyModel = car.CarParams.SafetyModel.hyundai
ret.enableCruise = True # stock acc
@ -143,7 +140,7 @@ class CarInterface(object):
ret.brakeMaxBP = [0.]
ret.brakeMaxV = [1.]
ret.enableCamera = not any(x for x in CAMERA_MSGS if x in fingerprint) or is_panda_black
ret.enableCamera = is_ecu_disconnected(fingerprint[0], FINGERPRINTS, ECU_FINGERPRINT, candidate, ECU.CAM) or has_relay
ret.openpilotLongitudinalControl = False
ret.steerLimitAlert = False

View File

@ -1,18 +1,5 @@
#!/usr/bin/env python
import os
import time
from cereal import car
#!/usr/bin/env python3
from selfdrive.car.interfaces import RadarInterfaceBase
class RadarInterface(object):
def __init__(self, CP):
# radar
self.pts = {}
self.delay = 0.1
def update(self, can_strings):
ret = car.RadarData.new_message()
if 'NO_RADAR_SLEEP' not in os.environ:
time.sleep(0.05) # radard runs on RI updates
return ret
class RadarInterface(RadarInterfaceBase):
pass

View File

@ -25,7 +25,7 @@ class Buttons:
FINGERPRINTS = {
CAR.ELANTRA: [{
66: 8, 67: 8, 68: 8, 127: 8, 273: 8, 274: 8, 275: 8, 339: 8, 356: 4, 399: 8, 512: 6, 544: 8, 593: 8, 608: 8, 688: 5, 790: 8, 809: 8, 897: 8, 899: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1170: 8, 1265: 4, 1280: 1, 1282: 4, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1314: 8, 1322: 8, 1345: 8, 1349: 8, 1351: 8, 1353: 8, 1363: 8, 1366: 8, 1367: 8, 1369: 8, 1407: 8, 1415: 8, 1419: 8, 1425: 2, 1427: 6, 1440: 8, 1456: 4, 1472: 8, 1486: 8, 1487: 8, 1491: 8, 1530: 8, 1532: 5, 2001: 8, 2003: 8, 2004: 8, 2009: 8, 2012: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8
66: 8, 67: 8, 68: 8, 127: 8, 273: 8, 274: 8, 275: 8, 339: 8, 356: 4, 399: 8, 512: 6, 544: 8, 593: 8, 608: 8, 688: 5, 790: 8, 809: 8, 897: 8, 832: 8, 899: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1170: 8, 1265: 4, 1280: 1, 1282: 4, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1314: 8, 1322: 8, 1345: 8, 1349: 8, 1351: 8, 1353: 8, 1363: 8, 1366: 8, 1367: 8, 1369: 8, 1407: 8, 1415: 8, 1419: 8, 1425: 2, 1427: 6, 1440: 8, 1456: 4, 1472: 8, 1486: 8, 1487: 8, 1491: 8, 1530: 8, 1532: 5, 2001: 8, 2003: 8, 2004: 8, 2009: 8, 2012: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8
}],
CAR.GENESIS: [{
67: 8, 68: 8, 304: 8, 320: 8, 339: 8, 356: 4, 544: 7, 593: 8, 608: 8, 688: 5, 809: 8, 832: 8, 854: 7, 870: 7, 871: 8, 872: 5, 897: 8, 902: 8, 903: 6, 916: 8, 1024: 2, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1168: 7, 1170: 8, 1173: 8, 1184: 8, 1265: 4, 1280: 1, 1287: 4, 1292: 8, 1312: 8, 1322: 8, 1331: 8, 1332: 8, 1333: 8, 1334: 8, 1335: 8, 1342: 6, 1345: 8, 1363: 8, 1369: 8, 1370: 8, 1371: 8, 1378: 4, 1384: 5, 1407: 8, 1419: 8, 1427: 6, 1434: 2, 1456: 4
@ -46,12 +46,17 @@ FINGERPRINTS = {
67: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 544: 8, 593: 8, 608: 8, 688: 6, 809: 8, 832: 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1155: 8, 1156: 8, 1162: 8, 1164: 8, 1168: 7, 1170: 8, 1173: 8, 1183: 8, 1186: 2, 1191: 2, 1227: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1379: 8, 1384: 8, 1407: 8, 1414: 3, 1419: 8, 1427: 6, 1456: 4, 1470: 8
},
{
67: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 544: 8, 593: 8, 608: 8, 688: 6, 764: 8, 809: 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1064: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1155: 8, 1162: 8, 1164: 8, 1168: 7, 1170: 8, 1173: 8, 1180: 8, 1183: 8, 1186: 2, 1227: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1371: 8, 1378: 8, 1384: 8, 1407: 8, 1414: 3, 1419: 8, 1427: 6, 1456: 4, 1470: 8, 1988: 8, 2000: 8, 2004: 8, 2008: 8, 2012: 8
67: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 544: 8, 593: 8, 608: 8, 688: 6, 764: 8, 809: 8, 832: 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1064: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1155: 8, 1162: 8, 1164: 8, 1168: 7, 1170: 8, 1173: 8, 1180: 8, 1183: 8, 1186: 2, 1227: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1371: 8, 1378: 8, 1384: 8, 1407: 8, 1414: 3, 1419: 8, 1427: 6, 1456: 4, 1470: 8, 1988: 8, 2000: 8, 2004: 8, 2008: 8, 2012: 8
}
],
}
CAMERA_MSGS = [832, 1156, 1191, 1342]
class ECU:
CAM = 0
ECU_FINGERPRINT = {
ECU.CAM: [832, 1156, 1191, 1342]
}
CHECKSUM = {
"crc8": [CAR.SANTA_FE],

View File

@ -0,0 +1,39 @@
import os
import time
from cereal import car
from selfdrive.car import gen_empty_fingerprint
# generic car and radar interfaces
class CarInterfaceBase():
def __init__(self, CP, CarController):
pass
@staticmethod
def calc_accel_override(a_ego, a_target, v_ego, v_target):
return 1.
@staticmethod
def get_params(candidate, fingerprint=gen_empty_fingerprint(), vin="", has_relay=False):
raise NotImplementedError
# returns a car.CarState, pass in car.CarControl
def update(self, c, can_strings):
raise NotImplementedError
# return sendcan, pass in a car.CarControl
def apply(self, c):
raise NotImplementedError
class RadarInterfaceBase():
def __init__(self, CP):
self.pts = {}
self.delay = 0
def update(self, can_strings):
ret = car.RadarData.new_message()
if 'NO_RADAR_SLEEP' not in os.environ:
time.sleep(0.05) # radard runs on RI updates
return ret

View File

@ -1,9 +1,11 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from cereal import car
from selfdrive.config import Conversions as CV
from selfdrive.services import service_list
from selfdrive.swaglog import cloudlog
import selfdrive.messaging as messaging
from selfdrive.car import gen_empty_fingerprint
from selfdrive.car.interfaces import CarInterfaceBase
# mocked car interface to work with chffrplus
TS = 0.01 # 100Hz
@ -12,7 +14,7 @@ YAW_FR = 0.2 # ~0.8s time constant on yaw rate filter
LPG = 2 * 3.1415 * YAW_FR * TS / (1 + 2 * 3.1415 * YAW_FR * TS)
class CarInterface(object):
class CarInterface(CarInterfaceBase):
def __init__(self, CP, CarController):
self.CP = CP
@ -34,11 +36,7 @@ class CarInterface(object):
return accel
@staticmethod
def calc_accel_override(a_ego, a_target, v_ego, v_target):
return 1.0
@staticmethod
def get_params(candidate, fingerprint, vin="", is_panda_black=False):
def get_params(candidate, fingerprint=gen_empty_fingerprint(), vin="", has_relay=False):
ret = car.CarParams.new_message()

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