Compare commits
31 Commits
master
...
latency_lo
Author | SHA1 | Date |
---|---|---|
Lukas Petersson | 1fee24c612 | |
Lukas Petersson | eb4dd2cb6e | |
Lukas Petersson | 0d989fb2e5 | |
Comma Device | 86139f0c52 | |
Lukas Petersson | 5bf4290d70 | |
Lukas Petersson | 861a545a46 | |
Comma Device | d5b1e31335 | |
Lukas Petersson | 5e44d0460a | |
Lukas Petersson | c4fdcb6f8d | |
Lukas Petersson | 1a3cb43a67 | |
Comma Device | 7b7655079a | |
Lukas Petersson | 6922fa21a4 | |
Comma Device | 25f07d207f | |
Comma Device | c6f082ca74 | |
Lukas Petersson | e66b2bf70a | |
Lukas Petersson | 1b50e24f65 | |
Lukas Petersson | 4e898fe88f | |
Comma Device | 548e6159fb | |
Comma Device | 08c0896f6a | |
Lukas Petersson | 6f4d041e83 | |
Lukas Petersson | 790a58c4fb | |
Lukas Petersson | 852702311d | |
Lukas Petersson | 419da793af | |
Lukas Petersson | 932778e21b | |
Lukas Petersson | 37925ac9f6 | |
Lukas Petersson | 2d7726a82b | |
Lukas Petersson | 9892fa63fe | |
Lukas Petersson | 337219c9f3 | |
Lukas Petersson | aad0b12223 | |
Lukas Petersson | 75adb2d076 | |
Bruce Wayne | ccfb061870 |
|
@ -22,8 +22,8 @@ Route: [a route with the bug fix]
|
||||||
<!--- ***** Template: Car port *****
|
<!--- ***** Template: Car port *****
|
||||||
|
|
||||||
**Checklist**
|
**Checklist**
|
||||||
- [ ] added entry to CarInfo in selfdrive/car/*/values.py and ran `selfdrive/car/docs.py` to generate new docs
|
- [ ] added to README
|
||||||
- [ ] test route added to [routes.py](https://github.com/commaai/openpilot/blob/master/selfdrive/car/tests/routes.py)
|
- [ ] test route added to [test_routes.py](https://github.com/commaai/openpilot/blob/master/selfdrive/test/test_routes.py)
|
||||||
- [ ] route with openpilot:
|
- [ ] route with openpilot:
|
||||||
- [ ] route with stock system:
|
- [ ] route with stock system:
|
||||||
|
|
||||||
|
|
|
@ -244,8 +244,7 @@ jobs:
|
||||||
run: eval "$BUILD"
|
run: eval "$BUILD"
|
||||||
- name: Run unit tests
|
- name: Run unit tests
|
||||||
run: |
|
run: |
|
||||||
${{ env.RUN }} "export SKIP_LONG_TESTS=1 && \
|
${{ env.RUN }} "scons -j$(nproc) --test && \
|
||||||
scons -j$(nproc) --test && \
|
|
||||||
$UNIT_TEST common && \
|
$UNIT_TEST common && \
|
||||||
$UNIT_TEST opendbc/can && \
|
$UNIT_TEST opendbc/can && \
|
||||||
$UNIT_TEST selfdrive/boardd && \
|
$UNIT_TEST selfdrive/boardd && \
|
||||||
|
@ -384,7 +383,7 @@ jobs:
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
path: /tmp/comma_download_cache
|
path: /tmp/comma_download_cache
|
||||||
key: car_models-${{ hashFiles('selfdrive/car/tests/test_models.py', 'selfdrive/car/tests/routes.py') }}-${{ matrix.job }}
|
key: car_models-${{ hashFiles('selfdrive/car/tests/test_models.py', 'selfdrive/test/test_routes.py') }}-${{ matrix.job }}
|
||||||
- name: Cache scons
|
- name: Cache scons
|
||||||
id: scons-cache
|
id: scons-cache
|
||||||
# TODO: Change the version to the released version when https://github.com/actions/cache/pull/489 (or 571) is merged.
|
# TODO: Change the version to the released version when https://github.com/actions/cache/pull/489 (or 571) is merged.
|
||||||
|
|
|
@ -35,6 +35,7 @@ a.out
|
||||||
config.json
|
config.json
|
||||||
clcache
|
clcache
|
||||||
compile_commands.json
|
compile_commands.json
|
||||||
|
tools/latency_logging/timestamps.json
|
||||||
|
|
||||||
persist
|
persist
|
||||||
board/obj/
|
board/obj/
|
||||||
|
|
|
@ -54,7 +54,7 @@ confidence=
|
||||||
# --enable=similarities". If you want to run only the classes checker, but have
|
# --enable=similarities". If you want to run only the classes checker, but have
|
||||||
# no Warning level messages displayed, use"--disable=all --enable=classes
|
# no Warning level messages displayed, use"--disable=all --enable=classes
|
||||||
# --disable=W"
|
# --disable=W"
|
||||||
disable=C,R,W0613,W0511,W0212,W0201,W0106,W0603,W0621,W0703,W1201,W1203,E1136,W1514
|
disable=C,R,W0613,W0511,W0212,W0201,W0311,W0106,W0603,W0621,W0703,W1201,W1203,E1136,W1514
|
||||||
|
|
||||||
|
|
||||||
# Enable the message, report, category or checker with the given id(s). You can
|
# Enable the message, report, category or checker with the given id(s). You can
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
Version 0.8.14 (2022-0X-XX)
|
Version 0.8.14 (2022-0X-XX)
|
||||||
========================
|
========================
|
||||||
* bigmodel!
|
* bigmodel!
|
||||||
* Toyota Alphard Hybrid 2021 support
|
|
||||||
* Toyota Avalon Hybrid 2022 support
|
|
||||||
|
|
||||||
Version 0.8.13 (2022-02-18)
|
Version 0.8.13 (2022-02-18)
|
||||||
========================
|
========================
|
||||||
|
|
2
cereal
|
@ -1 +1 @@
|
||||||
Subproject commit a818779f1a55c6bf53fa0692e31111585662b722
|
Subproject commit f546024f76a1d7d8f502f8cf67cb847e29327ba2
|
|
@ -36,8 +36,8 @@ class TestSimpleKalman(unittest.TestCase):
|
||||||
self.assertEqual(self.kf.x, [[1.0], [1.0]])
|
self.assertEqual(self.kf.x, [[1.0], [1.0]])
|
||||||
|
|
||||||
def update_returns_state(self):
|
def update_returns_state(self):
|
||||||
x = self.kf.update(100)
|
x = self.kf.update(100)
|
||||||
self.assertEqual(x, self.kf.x)
|
self.assertEqual(x, self.kf.x)
|
||||||
|
|
||||||
def test_old_equal_new(self):
|
def test_old_equal_new(self):
|
||||||
for _ in range(1000):
|
for _ in range(1000):
|
||||||
|
|
|
@ -7,9 +7,11 @@ import uuid
|
||||||
import socket
|
import socket
|
||||||
import logging
|
import logging
|
||||||
import traceback
|
import traceback
|
||||||
|
import time
|
||||||
from threading import local
|
from threading import local
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict, defaultdict
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
from common.realtime import sec_since_boot
|
||||||
|
|
||||||
def json_handler(obj):
|
def json_handler(obj):
|
||||||
# if isinstance(obj, (datetime.date, datetime.time)):
|
# if isinstance(obj, (datetime.date, datetime.time)):
|
||||||
|
@ -163,6 +165,17 @@ class SwagLogger(logging.Logger):
|
||||||
else:
|
else:
|
||||||
self.info(evt)
|
self.info(evt)
|
||||||
|
|
||||||
|
def timestamp(self, event_name, *args, **kwargs):
|
||||||
|
tstp = NiceOrderedDict()
|
||||||
|
tstp['timestamp'] = NiceOrderedDict()
|
||||||
|
tstp['timestamp']["event"] = event_name
|
||||||
|
tstp['timestamp']["time"] = sec_since_boot()*1e9
|
||||||
|
tstp['timestamp']["translate"] = False
|
||||||
|
if args:
|
||||||
|
tstp['timestamp']['args'] = args
|
||||||
|
tstp['timestamp'].update(kwargs)
|
||||||
|
self.debug(tstp)
|
||||||
|
|
||||||
def findCaller(self, stack_info=False, stacklevel=1):
|
def findCaller(self, stack_info=False, stacklevel=1):
|
||||||
"""
|
"""
|
||||||
Find the stack frame of the caller so that we can note the source
|
Find the stack frame of the caller so that we can note the source
|
||||||
|
@ -172,33 +185,33 @@ class SwagLogger(logging.Logger):
|
||||||
#On some versions of IronPython, currentframe() returns None if
|
#On some versions of IronPython, currentframe() returns None if
|
||||||
#IronPython isn't run with -X:Frames.
|
#IronPython isn't run with -X:Frames.
|
||||||
if f is not None:
|
if f is not None:
|
||||||
f = f.f_back
|
f = f.f_back
|
||||||
orig_f = f
|
orig_f = f
|
||||||
while f and stacklevel > 1:
|
while f and stacklevel > 1:
|
||||||
f = f.f_back
|
f = f.f_back
|
||||||
stacklevel -= 1
|
stacklevel -= 1
|
||||||
if not f:
|
if not f:
|
||||||
f = orig_f
|
f = orig_f
|
||||||
rv = "(unknown file)", 0, "(unknown function)", None
|
rv = "(unknown file)", 0, "(unknown function)", None
|
||||||
while hasattr(f, "f_code"):
|
while hasattr(f, "f_code"):
|
||||||
co = f.f_code
|
co = f.f_code
|
||||||
filename = os.path.normcase(co.co_filename)
|
filename = os.path.normcase(co.co_filename)
|
||||||
|
|
||||||
# TODO: is this pylint exception correct?
|
# TODO: is this pylint exception correct?
|
||||||
if filename == _srcfile: # pylint: disable=comparison-with-callable
|
if filename == _srcfile: # pylint: disable=comparison-with-callable
|
||||||
f = f.f_back
|
f = f.f_back
|
||||||
continue
|
continue
|
||||||
sinfo = None
|
sinfo = None
|
||||||
if stack_info:
|
if stack_info:
|
||||||
sio = io.StringIO()
|
sio = io.StringIO()
|
||||||
sio.write('Stack (most recent call last):\n')
|
sio.write('Stack (most recent call last):\n')
|
||||||
traceback.print_stack(f, file=sio)
|
traceback.print_stack(f, file=sio)
|
||||||
sinfo = sio.getvalue()
|
sinfo = sio.getvalue()
|
||||||
if sinfo[-1] == '\n':
|
if sinfo[-1] == '\n':
|
||||||
sinfo = sinfo[:-1]
|
sinfo = sinfo[:-1]
|
||||||
sio.close()
|
sio.close()
|
||||||
rv = (co.co_filename, f.f_lineno, co.co_name, sinfo)
|
rv = (co.co_filename, f.f_lineno, co.co_name, sinfo)
|
||||||
break
|
break
|
||||||
return rv
|
return rv
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
394
docs/CARS.md
|
@ -1,222 +1,186 @@
|
||||||
# Supported Cars
|
# Supported Cars
|
||||||
|
|
||||||
A supported vehicle is one that just works when you install a comma device. Every car performs differently with openpilot, but all supported cars should provide a better experience than any stock system.
|
## comma.ai supported cars
|
||||||
|
|
||||||
Cars are organized into three tiers:
|
| Make | Model (US Market Reference) | Supported Package | ACC | No ACC accel below | No ALC below |
|
||||||
|
| ----------| ------------------------------| ------------------| -----------------| -------------------| ------------------|
|
||||||
|
| Acura | ILX 2016-19 | AcuraWatch Plus | openpilot | 25mph<sup>1</sup> | 25mph |
|
||||||
|
| Acura | RDX 2016-18 | AcuraWatch Plus | openpilot | 25mph<sup>1</sup> | 12mph |
|
||||||
|
| Acura | RDX 2019-21 | All | Stock | 0mph | 3mph |
|
||||||
|
| Honda | Accord 2018-21 | All | Stock | 0mph | 3mph |
|
||||||
|
| Honda | Accord Hybrid 2018-21 | All | Stock | 0mph | 3mph |
|
||||||
|
| Honda | Civic Hatchback 2017-21 | Honda Sensing | Stock | 0mph | 12mph |
|
||||||
|
| Honda | Civic Coupe 2016-18 | Honda Sensing | openpilot | 0mph | 12mph |
|
||||||
|
| Honda | Civic Coupe 2019-20 | All | Stock | 0mph | 2mph<sup>2</sup> |
|
||||||
|
| Honda | Civic Sedan 2016-18 | Honda Sensing | openpilot | 0mph | 12mph |
|
||||||
|
| Honda | Civic Sedan 2019-20 | All | Stock | 0mph | 2mph<sup>2</sup> |
|
||||||
|
| Honda | CR-V 2015-16 | Touring | openpilot | 25mph<sup>1</sup> | 12mph |
|
||||||
|
| Honda | CR-V 2017-21 | Honda Sensing | Stock | 0mph | 12mph |
|
||||||
|
| Honda | CR-V Hybrid 2017-2019 | Honda Sensing | Stock | 0mph | 12mph |
|
||||||
|
| Honda | e 2020 | All | Stock | 0mph | 3mph |
|
||||||
|
| Honda | Fit 2018-19 | Honda Sensing | openpilot | 25mph<sup>1</sup> | 12mph |
|
||||||
|
| Honda | Freed 2020 | Honda Sensing | openpilot | 25mph<sup>1</sup> | 12mph |
|
||||||
|
| Honda | HR-V 2019-20 | Honda Sensing | openpilot | 25mph<sup>1</sup> | 12mph |
|
||||||
|
| Honda | Insight 2019-21 | All | Stock | 0mph | 3mph |
|
||||||
|
| Honda | Inspire 2018 | All | Stock | 0mph | 3mph |
|
||||||
|
| Honda | Odyssey 2018-20 | Honda Sensing | openpilot | 25mph<sup>1</sup> | 0mph |
|
||||||
|
| Honda | Passport 2019-21 | All | openpilot | 25mph<sup>1</sup> | 12mph |
|
||||||
|
| Honda | Pilot 2016-21 | Honda Sensing | openpilot | 25mph<sup>1</sup> | 12mph |
|
||||||
|
| Honda | Ridgeline 2017-21 | Honda Sensing | openpilot | 25mph<sup>1</sup> | 12mph |
|
||||||
|
| Hyundai | Palisade 2020-21 | All | Stock | 0mph | 0mph |
|
||||||
|
| Hyundai | Sonata 2020-22 | All | Stock | 0mph | 0mph |
|
||||||
|
| Lexus | CT Hybrid 2017-18 | LSS | Stock<sup>3</sup>| 0mph | 0mph |
|
||||||
|
| Lexus | ES 2019-21 | All | openpilot | 0mph | 0mph |
|
||||||
|
| Lexus | ES Hybrid 2017-18 | LSS | Stock<sup>3</sup>| 0mph | 0mph |
|
||||||
|
| Lexus | ES Hybrid 2019-21 | All | openpilot | 0mph | 0mph |
|
||||||
|
| Lexus | IS 2017-2019 | All | Stock | 22mph | 0mph |
|
||||||
|
| Lexus | NX 2018-2019 | All | Stock<sup>3</sup>| 0mph | 0mph |
|
||||||
|
| Lexus | NX 2020 | All | openpilot | 0mph | 0mph |
|
||||||
|
| Lexus | NX Hybrid 2018-19 | All | Stock<sup>3</sup>| 0mph | 0mph |
|
||||||
|
| Lexus | RC 2020 | All | Stock | 22mph | 0mph |
|
||||||
|
| Lexus | RX 2016-18 | All | Stock<sup>3</sup>| 0mph | 0mph |
|
||||||
|
| Lexus | RX 2020-21 | All | openpilot | 0mph | 0mph |
|
||||||
|
| Lexus | RX Hybrid 2016-19 | All | Stock<sup>3</sup>| 0mph | 0mph |
|
||||||
|
| Lexus | RX Hybrid 2020-21 | All | openpilot | 0mph | 0mph |
|
||||||
|
| Lexus | UX Hybrid 2019-21 | All | openpilot | 0mph | 0mph |
|
||||||
|
| Toyota | Alphard 2019-20 | All | openpilot | 0mph | 0mph |
|
||||||
|
| Toyota | Avalon 2016-18 | TSS-P | Stock<sup>3</sup>| 20mph<sup>1</sup> | 0mph |
|
||||||
|
| Toyota | Avalon 2019-21 | TSS-P | Stock<sup>3</sup>| 0mph | 0mph |
|
||||||
|
| Toyota | Avalon 2022 | All | openpilot | 0mph | 0mph |
|
||||||
|
| Toyota | Avalon Hybrid 2019-21 | TSS-P | Stock<sup>3</sup>| 0mph | 0mph |
|
||||||
|
| Toyota | Camry 2018-20 | All | Stock | 0mph<sup>4</sup> | 0mph |
|
||||||
|
| Toyota | Camry 2021-22 | All | openpilot | 0mph<sup>4</sup> | 0mph |
|
||||||
|
| Toyota | Camry Hybrid 2018-20 | All | Stock | 0mph<sup>4</sup> | 0mph |
|
||||||
|
| Toyota | Camry Hybrid 2021-22 | All | openpilot | 0mph | 0mph |
|
||||||
|
| Toyota | C-HR 2017-21 | All | Stock | 0mph | 0mph |
|
||||||
|
| Toyota | C-HR Hybrid 2017-19 | All | Stock | 0mph | 0mph |
|
||||||
|
| Toyota | Corolla 2017-19 | All | Stock<sup>3</sup>| 20mph<sup>1</sup> | 0mph |
|
||||||
|
| Toyota | Corolla 2020-22 | All | openpilot | 0mph | 0mph |
|
||||||
|
| Toyota | Corolla Hatchback 2019-22 | All | openpilot | 0mph | 0mph |
|
||||||
|
| Toyota | Corolla Hybrid 2020-22 | All | openpilot | 0mph | 0mph |
|
||||||
|
| Toyota | Highlander 2017-19 | All | Stock<sup>3</sup>| 0mph | 0mph |
|
||||||
|
| Toyota | Highlander 2020-22 | All | openpilot | 0mph | 0mph |
|
||||||
|
| Toyota | Highlander Hybrid 2017-19 | All | Stock<sup>3</sup>| 0mph | 0mph |
|
||||||
|
| Toyota | Highlander Hybrid 2020-22 | All | openpilot | 0mph | 0mph |
|
||||||
|
| Toyota | Mirai 2021 | All | openpilot | 0mph | 0mph |
|
||||||
|
| Toyota | Prius 2016-20 | TSS-P | Stock<sup>3</sup>| 0mph | 0mph |
|
||||||
|
| Toyota | Prius 2021-22 | All | openpilot | 0mph | 0mph |
|
||||||
|
| Toyota | Prius v 2017 | TSS-P | Stock<sup>3</sup>| 20mph<sup>1</sup> | 0mph |
|
||||||
|
| Toyota | Prius Prime 2017-20 | All | Stock<sup>3</sup>| 0mph | 0mph |
|
||||||
|
| Toyota | Prius Prime 2021-22 | All | openpilot | 0mph | 0mph |
|
||||||
|
| Toyota | Rav4 2016-18 | TSS-P | Stock<sup>3</sup>| 20mph<sup>1</sup> | 0mph |
|
||||||
|
| Toyota | Rav4 2019-21 | All | openpilot | 0mph | 0mph |
|
||||||
|
| Toyota | Rav4 Hybrid 2016-18 | TSS-P | Stock<sup>3</sup>| 0mph | 0mph |
|
||||||
|
| Toyota | Rav4 Hybrid 2019-21 | All | openpilot | 0mph | 0mph |
|
||||||
|
| Toyota | Sienna 2018-20 | All | Stock<sup>3</sup>| 0mph | 0mph |
|
||||||
|
|
||||||
- Gold - The best openpilot experience. Great highway driving and beyond.
|
<sup>1</sup>[Comma Pedal](https://github.com/commaai/openpilot/wiki/comma-pedal) is used to provide stop-and-go capability to some of the openpilot-supported cars that don't currently support stop-and-go. ***NOTE: The Comma Pedal is not officially supported by [comma](https://comma.ai).*** <br />
|
||||||
- Silver - A solid highway driving experience, but is limited by stock longitudinal. May be upgraded in the future.
|
|
||||||
- Bronze - A good highway experience, but may have limited performance in traffic and on sharp turns.
|
|
||||||
|
|
||||||
How We Rate The Cars
|
|
||||||
---
|
|
||||||
|
|
||||||
### openpilot Adaptive Cruise Control (ACC)
|
|
||||||
- <a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a> - openpilot is able to control the gas and brakes.
|
|
||||||
- <a href="#"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a> - openpilot is able to control the gas and brakes with some restrictions.
|
|
||||||
- <a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a> - The gas and brakes are controlled by the car's stock Adaptive Cruise Control (ACC) system.
|
|
||||||
|
|
||||||
### Stop and Go
|
|
||||||
- <a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a> - Adaptive Cruise Control (ACC) operates down to 0 mph.
|
|
||||||
- <a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a> - Adaptive Cruise Control (ACC) available only above certain speeds. See your car's manual for the minimum speed.
|
|
||||||
|
|
||||||
### Steer to 0
|
|
||||||
- <a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a> - openpilot can control the steering wheel down to 0 mph.
|
|
||||||
- <a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a> - No steering control below certain speeds.
|
|
||||||
|
|
||||||
### Steering Torque
|
|
||||||
- <a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a> - Car has enough steering torque for comfortable highway driving.
|
|
||||||
- <a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a> - Limited ability to make turns.
|
|
||||||
|
|
||||||
### Actively Maintained
|
|
||||||
- <a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a> - Mainline software support, harness hardware sold by comma, lots of users, primary development target.
|
|
||||||
- <a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a> - Low user count, community maintained, harness hardware not sold by comma.
|
|
||||||
|
|
||||||
**All supported cars can move between the tiers as support changes.**
|
|
||||||
|
|
||||||
## Gold Cars
|
|
||||||
|
|
||||||
|Make|Model|Supported Package|openpilot ACC|Stop and Go|Steer to 0|Steering Torque|Actively Maintained|
|
|
||||||
|---|---|---|:---:|:---:|:---:|:---:|:---:|
|
|
||||||
|Genesis|G70 2020|All|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Hyundai|Palisade 2020-21|All|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Hyundai|Santa Fe 2019-20|All|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Hyundai|Sonata 2020-22|All|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Hyundai|Sonata Hybrid 2021-22|All|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Kia|Niro Electric 2019-22|All|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Kia|Telluride 2020|SCC + LKAS|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Lexus|ES 2019-21|All|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Lexus|ES Hybrid 2019-21|All|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Lexus|NX 2020|All|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Lexus|RX 2020-21|All|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Lexus|RX Hybrid 2020-21|All|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Lexus|UX Hybrid 2019-21|All|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|Alphard 2019-20|All|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|Alphard Hybrid 2021|All|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|Avalon 2022|All|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|Avalon Hybrid 2022|All|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|Camry 2021-22|All|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>[<sup>4</sup>](#Footnotes)|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|Camry Hybrid 2021-22|All|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|Corolla 2020-22|All|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|Corolla Hatchback 2019-22|All|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|Corolla Hybrid 2020-22|All|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|Highlander 2020-22|All|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|Highlander Hybrid 2020-22|All|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|Mirai 2021|All|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|Prius 2021-22|All|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|Prius Prime 2021-22|All|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|RAV4 2019-21|All|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|RAV4 Hybrid 2019-21|All|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|
|
||||||
## Silver Cars
|
|
||||||
|
|
||||||
|Make|Model|Supported Package|openpilot ACC|Stop and Go|Steer to 0|Steering Torque|Actively Maintained|
|
|
||||||
|---|---|---|:---:|:---:|:---:|:---:|:---:|
|
|
||||||
|Audi|A3 2014-19|ACC + Lane Assist|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Audi|A3 Sportback e-tron 2017-18|ACC + Lane Assist|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Audi|Q2 2018|ACC + Lane Assist|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Audi|Q3 2020-21|ACC + Lane Assist|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Audi|S3 2015-17|ACC + Lane Assist|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Genesis|G70 2018|All|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Genesis|G80 2018|All|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Hyundai|Elantra 2021-22|SCC + LKAS|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Hyundai|Elantra Hybrid 2021|SCC + LKAS|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Hyundai|Ioniq Electric 2020|SCC + LKAS|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Hyundai|Ioniq Hybrid 2020-22|SCC + LFA|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Hyundai|Ioniq Plug-In Hybrid 2020-21|SCC + LKAS|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Hyundai|Kona 2020|SCC + LKAS|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Hyundai|Kona Electric 2018-19|SCC + LKAS|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Hyundai|Kona Hybrid 2020|SCC + LKAS|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Hyundai|Santa Fe 2021-22|All|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Hyundai|Santa Fe Hybrid 2022|All|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Hyundai|Santa Fe Plug-In Hybrid 2022|All|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Hyundai|Sonata 2018-19|SCC + LKAS|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Kia|Ceed 2019|SCC + LKAS|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Kia|Forte 2018-21|SCC + LKAS|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Kia|K5 2021-22|SCC + LFA|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Kia|Niro Hybrid 2021-22|SCC + LKAS|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Kia|Optima 2019|SCC + LKAS|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Kia|Seltos 2021|SCC + LKAS|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Kia|Sorento 2018-19|SCC + LKAS|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Kia|Stinger 2018|SCC + LKAS|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Lexus|CT Hybrid 2017-18|LSS|<a href="#"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#Footnotes)|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Lexus|ES Hybrid 2017-18|LSS|<a href="#"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#Footnotes)|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Lexus|NX 2018-19|All|<a href="#"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#Footnotes)|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Lexus|NX Hybrid 2018-19|All|<a href="#"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#Footnotes)|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Lexus|RX 2016-18|All|<a href="#"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#Footnotes)|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Lexus|RX Hybrid 2016-19|All|<a href="#"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#Footnotes)|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Mazda|CX-5 2022|All|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|SEAT|Ateca 2018|Driver Assistance|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|SEAT|Leon 2014-20|Driver Assistance|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|Avalon 2019-21|TSS-P|<a href="#"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#Footnotes)|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|Avalon Hybrid 2019-21|TSS-P|<a href="#"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#Footnotes)|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|C-HR 2017-21|All|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|C-HR Hybrid 2017-19|All|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|Camry 2018-20|All|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>[<sup>4</sup>](#Footnotes)|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|Camry Hybrid 2018-20|All|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>[<sup>4</sup>](#Footnotes)|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|Highlander 2017-19|All|<a href="#"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#Footnotes)|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|Highlander Hybrid 2017-19|All|<a href="#"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#Footnotes)|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|RAV4 Hybrid 2016-18|TSS-P|<a href="#"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#Footnotes)|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|Sienna 2018-20|All|<a href="#"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#Footnotes)|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Volkswagen|Arteon 2018, 2021[<sup>8</sup>](#Footnotes)|Driver Assistance|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Volkswagen|Atlas 2018-19, 2022[<sup>8</sup>](#Footnotes)|Driver Assistance|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Volkswagen|Golf 2015-20|Driver Assistance|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Volkswagen|Golf Alltrack 2017-18|Driver Assistance|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Volkswagen|Golf GTE 2016|Driver Assistance|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Volkswagen|Golf GTI 2018-20|Driver Assistance|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Volkswagen|Golf R 2016-19|Driver Assistance|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Volkswagen|Golf SportWagen 2015|Driver Assistance|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Volkswagen|Golf SportsVan 2016|Driver Assistance|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Volkswagen|Jetta 2018-21|Driver Assistance|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Volkswagen|Jetta GLI 2021|Driver Assistance|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Volkswagen|Passat 2016-18[<sup>7</sup>](#Footnotes)|Driver Assistance|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Volkswagen|Polo 2020|Driver Assistance|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Volkswagen|T-Cross 2021[<sup>8</sup>](#Footnotes)|Driver Assistance|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Volkswagen|T-Roc 2021[<sup>8</sup>](#Footnotes)|Driver Assistance|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Volkswagen|Taos 2022[<sup>8</sup>](#Footnotes)|Driver Assistance|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Volkswagen|Tiguan 2020-22[<sup>8</sup>](#Footnotes)|Driver Assistance|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Volkswagen|Touran 2017|Driver Assistance|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Volkswagen|e-Golf 2014, 2019-20|Driver Assistance|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Ĺ koda|Kamiq 2021[<sup>6</sup>](#Footnotes)|Driver Assistance|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Ĺ koda|Karoq 2019|Driver Assistance|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Ĺ koda|Kodiaq 2018-19|Driver Assistance|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Ĺ koda|Octavia 2015, 2018-19|Driver Assistance|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Ĺ koda|Octavia RS 2016|Driver Assistance|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Ĺ koda|Scala 2020|Driver Assistance|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Ĺ koda|Superb 2015-18|Driver Assistance|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|
|
||||||
## Bronze Cars
|
|
||||||
|
|
||||||
|Make|Model|Supported Package|openpilot ACC|Stop and Go|Steer to 0|Steering Torque|Actively Maintained|
|
|
||||||
|---|---|---|:---:|:---:|:---:|:---:|:---:|
|
|
||||||
|Acura|ILX 2016-19|AcuraWatch Plus|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Acura|RDX 2016-18|AcuraWatch Plus|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Acura|RDX 2019-21|All|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Cadillac|Escalade ESV 2016[<sup>1</sup>](#Footnotes)|ACC + LKAS|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Chevrolet|Volt 2017-18[<sup>1</sup>](#Footnotes)|Adaptive Cruise|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Chrysler|Pacifica 2017-18|Adaptive Cruise|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Chrysler|Pacifica 2020|Adaptive Cruise|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Chrysler|Pacifica Hybrid 2019-21|Adaptive Cruise|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|GMC|Acadia 2018[<sup>1</sup>](#Footnotes)|Adaptive Cruise|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Genesis|G90 2018|All|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|
|
|
||||||
|Honda|Accord 2018-21|All|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Honda|Accord Hybrid 2018-21|All|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Honda|CR-V 2015-16|Touring|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Honda|CR-V 2017-21|Honda Sensing|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Honda|CR-V Hybrid 2017-19|Honda Sensing|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Honda|Civic 2016-18|Honda Sensing|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Honda|Civic 2019-20|All|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>[<sup>2</sup>](#Footnotes)|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Honda|Civic Hatchback 2017-21|Honda Sensing|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Honda|Fit 2018-19|Honda Sensing|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Honda|Freed 2020|Honda Sensing|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Honda|HR-V 2019-20|Honda Sensing|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Honda|Insight 2019-21|All|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Honda|Inspire 2018|All|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Honda|Odyssey 2018-20|Honda Sensing|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Honda|Passport 2019-21|All|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Honda|Pilot 2016-21|Honda Sensing|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Honda|Ridgeline 2017-21|Honda Sensing|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Honda|e 2020|All|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Hyundai|Elantra 2017-19|SCC + LKAS|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Hyundai|Genesis 2015-16|SCC + LKAS|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Hyundai|Ioniq Electric 2019|SCC + LKAS|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Hyundai|Ioniq Hybrid 2017-19|SCC + LKAS|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Hyundai|Veloster 2019-20|SCC + LKAS|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Jeep|Grand Cherokee 2016-18|Adaptive Cruise|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Jeep|Grand Cherokee 2019-20|Adaptive Cruise|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Kia|Niro Plug-In Hybrid 2019|SCC + LKAS|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Kia|Optima 2017|SCC + LKAS|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Lexus|IS 2017-19|All|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Lexus|RC 2020|All|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Mazda|CX-9 2021|All|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Nissan|Altima 2019-20|ProPILOT|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Nissan|Leaf 2018-22|ProPILOT|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Nissan|Rogue 2018-20|ProPILOT|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Nissan|X-Trail 2017|ProPILOT|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Subaru|Ascent 2019|EyeSight|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Subaru|Crosstrek 2018-20|EyeSight|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Subaru|Forester 2019-21|EyeSight|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Subaru|Impreza 2017-19|EyeSight|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|Avalon 2016-18|TSS-P|<a href="#"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#Footnotes)|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|Corolla 2017-19|All|<a href="#"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#Footnotes)|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|Prius 2016-20|TSS-P|<a href="#"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#Footnotes)|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>5</sup>](#Footnotes)|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|Prius Prime 2017-20|All|<a href="#"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#Footnotes)|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>5</sup>](#Footnotes)|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|Prius v 2017|TSS-P|<a href="#"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#Footnotes)|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>5</sup>](#Footnotes)|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Toyota|RAV4 2016-18|TSS-P|<a href="#"><img valign="top" src="assets/icon-star-half.svg" width="22" /></a>[<sup>3</sup>](#Footnotes)|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Volkswagen|California 2021[<sup>8</sup>](#Footnotes)|Driver Assistance|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|Volkswagen|Caravelle 2020[<sup>8</sup>](#Footnotes)|Driver Assistance|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-empty.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|<a href="#"><img valign="top" src="assets/icon-star-full.svg" width="22" /></a>|
|
|
||||||
|
|
||||||
|
|
||||||
## Footnotes
|
|
||||||
<sup>1</sup>Requires an <a href="https://comma.ai/shop/products/comma-car-harness">OBD-II car harness</a> and <a href="https://github.com/commaai/openpilot/wiki/GM#hardware">community built ASCM harness</a>. <b><i>NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).</i></b> <br />
|
|
||||||
<sup>2</sup>2019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph. <br />
|
<sup>2</sup>2019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph. <br />
|
||||||
<sup>3</sup>When disconnecting the Driver Support Unit (DSU), openpilot Adaptive Cruise Control (ACC) will replace stock Adaptive Cruise Control (ACC). <b><i> NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).</i></b> <br />
|
<sup>3</sup>When disconnecting the Driver Support Unit (DSU), openpilot ACC will replace stock ACC. ***NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).*** <br />
|
||||||
<sup>4</sup>28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control. <br />
|
<sup>4</sup>28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control. <br />
|
||||||
<sup>5</sup>An inaccurate steering wheel angle sensor makes precise control difficult. <br />
|
|
||||||
<sup>6</sup>Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform. <br />
|
|
||||||
<sup>7</sup>Not including the USA/China market Passat, which is based on the (currently) unsupported PQ35/NMS platform. <br />
|
|
||||||
<sup>8</sup>Model-years 2021 and beyond may have a new camera harness design, which isn't yet available from the comma store. Before ordering, remove the Lane Assist camera cover and check to see if the connector is black (older design) or light brown (newer design). For the newer design, in the interim, choose "VW J533 Development" from the vehicle drop-down for a harness that integrates at the CAN gateway inside the dashboard. <br />
|
|
||||||
|
|
||||||
## Community Maintained Cars
|
## Community Maintained Cars and Features
|
||||||
Although they're not upstream, the community has openpilot running on other makes and models. See the 'Community Supported Models' section of each make [on our wiki](https://wiki.comma.ai/).
|
|
||||||
|
| Make | Model (US Market Reference) | Supported Package | ACC | No ACC accel below | No ALC below |
|
||||||
|
| ----------| --------------------------------| ------------------| -----------------| -------------------| -------------|
|
||||||
|
| Audi | A3 2014-19 | ACC + Lane Assist | Stock | 0mph | 0mph |
|
||||||
|
| Audi | A3 Sportback e-tron 2017-18 | ACC + Lane Assist | Stock | 0mph | 0mph |
|
||||||
|
| Audi | Q2 2018 | ACC + Lane Assist | Stock | 0mph | 0mph |
|
||||||
|
| Audi | Q3 2020-21 | ACC + Lane Assist | Stock | 0mph | 0mph |
|
||||||
|
| Audi | S3 2015-17 | ACC + Lane Assist | Stock | 0mph | 0mph |
|
||||||
|
| Cadillac | Escalade ESV 2016<sup>1</sup> | ACC + LKAS | openpilot | 0mph | 7mph |
|
||||||
|
| Chevrolet | Volt 2017-18<sup>1</sup> | Adaptive Cruise | openpilot | 0mph | 7mph |
|
||||||
|
| Chrysler | Pacifica 2017-18 | Adaptive Cruise | Stock | 0mph | 9mph |
|
||||||
|
| Chrysler | Pacifica 2020 | Adaptive Cruise | Stock | 0mph | 39mph |
|
||||||
|
| Chrysler | Pacifica Hybrid 2017-18 | Adaptive Cruise | Stock | 0mph | 9mph |
|
||||||
|
| Chrysler | Pacifica Hybrid 2019-21 | Adaptive Cruise | Stock | 0mph | 39mph |
|
||||||
|
| Genesis | G70 2018 | All | Stock | 0mph | 0mph |
|
||||||
|
| Genesis | G70 2020 | All | Stock | 0mph | 0mph |
|
||||||
|
| Genesis | G80 2018 | All | Stock | 0mph | 0mph |
|
||||||
|
| Genesis | G90 2018 | All | Stock | 0mph | 0mph |
|
||||||
|
| GMC | Acadia 2018<sup>1</sup> | Adaptive Cruise | openpilot | 0mph | 7mph |
|
||||||
|
| Hyundai | Elantra 2017-19 | SCC + LKAS | Stock | 19mph | 34mph |
|
||||||
|
| Hyundai | Elantra 2021-22 | SCC + LKAS | Stock | 0mph | 0mph |
|
||||||
|
| Hyundai | Elantra Hybrid 2021 | SCC + LKAS | Stock | 0mph | 0mph |
|
||||||
|
| Hyundai | Genesis 2015-16 | SCC + LKAS | Stock | 19mph | 37mph |
|
||||||
|
| Hyundai | Ioniq Electric 2019 | SCC + LKAS | Stock | 0mph | 32mph |
|
||||||
|
| Hyundai | Ioniq Electric 2020 | SCC + LKAS | Stock | 0mph | 0mph |
|
||||||
|
| Hyundai | Ioniq Hybrid 2017-19 | SCC + LKAS | Stock | 0mph | 32mph |
|
||||||
|
| Hyundai | Ioniq Hybrid 2020-22 | SCC + LFA | Stock | 0mph | 0mph |
|
||||||
|
| Hyundai | Ioniq PHEV 2020-21 | SCC + LKAS | Stock | 0mph | 0mph |
|
||||||
|
| Hyundai | Kona 2020 | SCC + LKAS | Stock | 0mph | 0mph |
|
||||||
|
| Hyundai | Kona EV 2018-19 | SCC + LKAS | Stock | 0mph | 0mph |
|
||||||
|
| Hyundai | Kona Hybrid 2020 | SCC + LKAS | Stock | 0mph | 0mph |
|
||||||
|
| Hyundai | Santa Fe 2019-20 | All | Stock | 0mph | 0mph |
|
||||||
|
| Hyundai | Santa Fe 2021-22 | All | Stock | 0mph | 0mph |
|
||||||
|
| Hyundai | Santa Fe Hybrid 2022 | All | Stock | 0mph | 0mph |
|
||||||
|
| Hyundai | Santa Fe Plug-in Hybrid 2022 | All | Stock | 0mph | 0mph |
|
||||||
|
| Hyundai | Sonata 2018-2019 | SCC + LKAS | Stock | 0mph | 0mph |
|
||||||
|
| Hyundai | Sonata Hybrid 2021-22 | All | Stock | 0mph | 0mph |
|
||||||
|
| Hyundai | Veloster 2019-20 | SCC + LKAS | Stock | 5mph | 0mph |
|
||||||
|
| Jeep | Grand Cherokee 2016-18 | Adaptive Cruise | Stock | 0mph | 9mph |
|
||||||
|
| Jeep | Grand Cherokee 2019-20 | Adaptive Cruise | Stock | 0mph | 39mph |
|
||||||
|
| Kia | Ceed 2019 | SCC + LKAS | Stock | 0mph | 0mph |
|
||||||
|
| Kia | Forte 2018-21 | SCC + LKAS | Stock | 0mph | 0mph |
|
||||||
|
| Kia | K5 2021-22 | SCC + LFA | Stock | 0mph | 0mph |
|
||||||
|
| Kia | Niro EV 2019-22 | All | Stock | 0mph | 0mph |
|
||||||
|
| Kia | Niro Hybrid 2021-22 | SCC + LKAS | Stock | 0mph | 0mph |
|
||||||
|
| Kia | Niro PHEV 2019 | SCC + LKAS | Stock | 10mph | 32mph |
|
||||||
|
| Kia | Optima 2017 | SCC + LKAS | Stock | 0mph | 32mph |
|
||||||
|
| Kia | Optima 2019 | SCC + LKAS | Stock | 0mph | 0mph |
|
||||||
|
| Kia | Seltos 2021 | SCC + LKAS | Stock | 0mph | 0mph |
|
||||||
|
| Kia | Sorento 2018-19 | SCC + LKAS | Stock | 0mph | 0mph |
|
||||||
|
| Kia | Stinger 2018 | SCC + LKAS | Stock | 0mph | 0mph |
|
||||||
|
| Kia | Telluride 2020 | SCC + LKAS | Stock | 0mph | 0mph |
|
||||||
|
| Mazda | CX-5 2022 | All | Stock | 0mph | 0mph |
|
||||||
|
| Mazda | CX-9 2021 | All | Stock | 0mph | 28mph |
|
||||||
|
| Nissan | Altima 2019-20 | ProPILOT | Stock | 0mph | 0mph |
|
||||||
|
| Nissan | Leaf 2018-22 | ProPILOT | Stock | 0mph | 0mph |
|
||||||
|
| Nissan | Rogue 2018-20 | ProPILOT | Stock | 0mph | 0mph |
|
||||||
|
| Nissan | X-Trail 2017 | ProPILOT | Stock | 0mph | 0mph |
|
||||||
|
| SEAT | Ateca 2018 | Driver Assistance | Stock | 0mph | 0mph |
|
||||||
|
| SEAT | Leon 2014-2020 | Driver Assistance | Stock | 0mph | 0mph |
|
||||||
|
| Subaru | Ascent 2019 | EyeSight | Stock | 0mph | 0mph |
|
||||||
|
| Subaru | Crosstrek 2018-20 | EyeSight | Stock | 0mph | 0mph |
|
||||||
|
| Subaru | Forester 2019-21 | EyeSight | Stock | 0mph | 0mph |
|
||||||
|
| Subaru | Impreza 2017-19 | EyeSight | Stock | 0mph | 0mph |
|
||||||
|
| Ĺ koda | Kamiq 2021<sup>2</sup> | Driver Assistance | Stock | 0mph | 0mph |
|
||||||
|
| Ĺ koda | Karoq 2019 | Driver Assistance | Stock | 0mph | 0mph |
|
||||||
|
| Ĺ koda | Kodiaq 2018-19 | Driver Assistance | Stock | 0mph | 0mph |
|
||||||
|
| Ĺ koda | Octavia 2015, 2018-19 | Driver Assistance | Stock | 0mph | 0mph |
|
||||||
|
| Ĺ koda | Octavia RS 2016 | Driver Assistance | Stock | 0mph | 0mph |
|
||||||
|
| Ĺ koda | Scala 2020 | Driver Assistance | Stock | 0mph | 0mph |
|
||||||
|
| Ĺ koda | Superb 2015-18 | Driver Assistance | Stock | 0mph | 0mph |
|
||||||
|
| Volkswagen| Arteon 2018, 2021<sup>4</sup> | Driver Assistance | Stock | 0mph | 0mph |
|
||||||
|
| Volkswagen| Atlas 2018-19, 2022<sup>4</sup> | Driver Assistance | Stock | 0mph | 0mph |
|
||||||
|
| Volkswagen| Caravelle 2020<sup>4</sup> | Driver Assistance | Stock | 0mph | 32mph |
|
||||||
|
| Volkswagen| California 2021<sup>4</sup> | Driver Assistance | Stock | 0mph | 32mph |
|
||||||
|
| Volkswagen| e-Golf 2014, 2019-20 | Driver Assistance | Stock | 0mph | 0mph |
|
||||||
|
| Volkswagen| Golf 2015-20 | Driver Assistance | Stock | 0mph | 0mph |
|
||||||
|
| Volkswagen| Golf Alltrack 2017-18 | Driver Assistance | Stock | 0mph | 0mph |
|
||||||
|
| Volkswagen| Golf GTE 2016 | Driver Assistance | Stock | 0mph | 0mph |
|
||||||
|
| Volkswagen| Golf GTI 2018-20 | Driver Assistance | Stock | 0mph | 0mph |
|
||||||
|
| Volkswagen| Golf R 2016-19 | Driver Assistance | Stock | 0mph | 0mph |
|
||||||
|
| Volkswagen| Golf SportsVan 2016 | Driver Assistance | Stock | 0mph | 0mph |
|
||||||
|
| Volkswagen| Golf SportWagen 2015 | Driver Assistance | Stock | 0mph | 0mph |
|
||||||
|
| Volkswagen| Jetta 2018-20 | Driver Assistance | Stock | 0mph | 0mph |
|
||||||
|
| Volkswagen| Jetta GLI 2021 | Driver Assistance | Stock | 0mph | 0mph |
|
||||||
|
| Volkswagen| Passat 2016-18<sup>3</sup> | Driver Assistance | Stock | 0mph | 0mph |
|
||||||
|
| Volkswagen| Polo 2020 | Driver Assistance | Stock | 0mph | 0mph |
|
||||||
|
| Volkswagen| T-Cross 2021<sup>4</sup> | Driver Assistance | Stock | 0mph | 0mph |
|
||||||
|
| Volkswagen| T-Roc 2021<sup>4</sup> | Driver Assistance | Stock | 0mph | 0mph |
|
||||||
|
| Volkswagen| Taos 2022<sup>4</sup> | Driver Assistance | Stock | 0mph | 0mph |
|
||||||
|
| Volkswagen| Tiguan 2020-22<sup>4</sup> | Driver Assistance | Stock | 0mph | 0mph |
|
||||||
|
| Volkswagen| Touran 2017 | Driver Assistance | Stock | 0mph | 0mph |
|
||||||
|
|
||||||
|
<sup>1</sup>Requires an [OBD-II car harness](https://comma.ai/shop/products/comma-car-harness) and [community built ASCM harness](https://github.com/commaai/openpilot/wiki/GM#hardware). ***NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).*** <br />
|
||||||
|
<sup>2</sup>Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform. <br />
|
||||||
|
<sup>3</sup>Not including the USA/China market Passat, which is based on the (currently) unsupported PQ35/NMS platform. <br />
|
||||||
|
<sup>4</sup>Model-years 2021 and beyond may have a new camera harness design, which isn't yet available from the comma store. Before ordering,
|
||||||
|
remove the Lane Assist camera cover and check to see if the connector is black (older design) or light brown (newer design). For the newer design,
|
||||||
|
in the interim, choose "VW J533 Development" from the vehicle drop-down for a harness that integrates at the CAN gateway inside the dashboard.<br />
|
||||||
|
Community Maintained Cars and Features are not verified by comma to meet our [safety model](SAFETY.md). Be extra cautious using them.
|
||||||
|
|
||||||
|
To promote a car from community maintained, it must meet a few requirements. We must own one from the brand, we must sell the harness for it, has full ISO26262 in both panda and openpilot, there must be a path forward for longitudinal control, it must have AEB still enabled, and it must support fingerprinting 2.0
|
||||||
|
|
||||||
|
Although they're not upstream, the community has openpilot running on other makes and models. See the 'Community Supported Models' section of each make [on our wiki](https://wiki.comma.ai/).
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M12.2584 16.8419L12 16.686L11.7416 16.8419L6.57613 19.9596L7.94693 14.0836L8.01549 13.7897L7.78739 13.5921L3.22308 9.63803L9.23227 9.12821L9.5327 9.10272L9.65036 8.82511L12 3.2813L14.3496 8.82511L14.4673 9.10272L14.7677 9.12821L20.7769 9.63803L16.2126 13.5921L15.9845 13.7897L16.0531 14.0836L17.4239 19.9596L12.2584 16.8419Z" stroke="#B7B7B7"/>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 457 B |
|
@ -1,3 +0,0 @@
|
||||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M12.2584 16.8419L12 16.686L11.7416 16.8419L6.57613 19.9596L7.94693 14.0836L8.01549 13.7897L7.78739 13.5921L3.22308 9.63803L9.23227 9.12821L9.5327 9.10272L9.65036 8.82511L12 3.2813L14.3496 8.82511L14.4673 9.10272L14.7677 9.12821L20.7769 9.63803L16.2126 13.5921L15.9845 13.7897L16.0531 14.0836L17.4239 19.9596L12.2584 16.8419Z" fill="#F5C543" stroke="#F0A43B"/>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 472 B |
|
@ -1,5 +0,0 @@
|
||||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M12 2V17.27L5.82 21L7.46 13.97L2 9.24L9.19 8.63L12 2Z" fill="#F5C543"/>
|
|
||||||
<path d="M12.2584 16.8419L12 16.686L11.7416 16.8419L6.57613 19.9596L7.94693 14.0836L8.01549 13.7897L7.78739 13.5921L3.22308 9.63803L9.23227 9.12821L9.5327 9.10272L9.65036 8.82511L12 3.2813L14.3496 8.82511L14.4673 9.10272L14.7677 9.12821L20.7769 9.63803L16.2126 13.5921L15.9845 13.7897L16.0531 14.0836L17.4239 19.9596L12.2584 16.8419Z" stroke="#B7B7B7"/>
|
|
||||||
<path d="M7.33226 18.9192L11 16.7055L12 16.1V17.27L5.82 21L7.46 13.97L2 9.24L9.19 8.63L12 2V4.6L11 6.92203L9.8754 9.57544L4.44617 10.0361L8.57098 13.6094L7.33226 18.9192Z" fill="#F0A43B"/>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 727 B |
|
@ -104,7 +104,14 @@ function tici_init {
|
||||||
sleep 3
|
sleep 3
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# setup governors
|
||||||
|
sudo su -c 'echo "performance" > /sys/class/devfreq/soc:qcom,memlat-cpu0/governor'
|
||||||
|
sudo su -c 'echo "performance" > /sys/class/devfreq/soc:qcom,memlat-cpu4/governor'
|
||||||
|
|
||||||
# TODO: move this to agnos
|
# TODO: move this to agnos
|
||||||
|
# network manager config
|
||||||
|
nmcli connection modify --temporary lte gsm.auto-config yes
|
||||||
|
nmcli connection modify --temporary lte gsm.home-only yes
|
||||||
sudo rm -f /data/etc/NetworkManager/system-connections/*.nmmeta
|
sudo rm -f /data/etc/NetworkManager/system-connections/*.nmmeta
|
||||||
|
|
||||||
# set success flag for current boot slot
|
# set success flag for current boot slot
|
||||||
|
|
|
@ -9,12 +9,6 @@ To view the architecture of the ONNX networks, you can use [netron](https://netr
|
||||||
* Channels 0,1,2,3 represent the full-res Y channel and are represented in numpy as Y[::2, ::2], Y[::2, 1::2], Y[1::2, ::2], and Y[1::2, 1::2]
|
* Channels 0,1,2,3 represent the full-res Y channel and are represented in numpy as Y[::2, ::2], Y[::2, 1::2], Y[1::2, ::2], and Y[1::2, 1::2]
|
||||||
* Channel 4 represents the half-res U channel
|
* Channel 4 represents the half-res U channel
|
||||||
* Channel 5 represents the half-res V channel
|
* Channel 5 represents the half-res V channel
|
||||||
* **wide image stream**
|
|
||||||
* Two consecutive images (256 * 512 * 3 in RGB) recorded at 20 Hz : 393216 = 2 * 6 * 128 * 256
|
|
||||||
* Each 256 * 512 image is represented in YUV420 with 6 channels : 6 * 128 * 256
|
|
||||||
* Channels 0,1,2,3 represent the full-res Y channel and are represented in numpy as Y[::2, ::2], Y[::2, 1::2], Y[1::2, ::2], and Y[1::2, 1::2]
|
|
||||||
* Channel 4 represents the half-res U channel
|
|
||||||
* Channel 5 represents the half-res V channel
|
|
||||||
* **desire**
|
* **desire**
|
||||||
* one-hot encoded vector to command model to execute certain actions, bit only needs to be sent for 1 frame : 8
|
* one-hot encoded vector to command model to execute certain actions, bit only needs to be sent for 1 frame : 8
|
||||||
* **traffic convention**
|
* **traffic convention**
|
||||||
|
|
2
panda
|
@ -1 +1 @@
|
||||||
Subproject commit 7104818e148494523e87fd74736748b6ffd0a7c4
|
Subproject commit e6722c7f99b8f7b9f81bb0216edb88cc2e5ad7c0
|
|
@ -100,7 +100,6 @@ selfdrive/boardd/set_time.py
|
||||||
selfdrive/boardd/pandad.py
|
selfdrive/boardd/pandad.py
|
||||||
|
|
||||||
selfdrive/car/__init__.py
|
selfdrive/car/__init__.py
|
||||||
selfdrive/car/docs_definitions.py
|
|
||||||
selfdrive/car/car_helpers.py
|
selfdrive/car/car_helpers.py
|
||||||
selfdrive/car/fingerprints.py
|
selfdrive/car/fingerprints.py
|
||||||
selfdrive/car/interfaces.py
|
selfdrive/car/interfaces.py
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
import os
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
|
|
||||||
from selfdrive.car.docs import get_tier_car_info
|
from common.basedir import BASEDIR
|
||||||
|
|
||||||
if __name__ == "__main__":
|
with open(os.path.join(BASEDIR, "docs/CARS.md")) as f:
|
||||||
tiers = get_tier_car_info()
|
lines = f.readlines()
|
||||||
cars = [car for tier_cars in tiers.values() for car in tier_cars]
|
cars = [l for l in lines if l.strip().startswith("|") and l.strip().endswith("|") and
|
||||||
|
"Make" not in l and any(c.isalpha() for c in l)]
|
||||||
|
|
||||||
make_count = Counter(l.make for l in cars)
|
make_count = Counter(l.split('|')[1].split('|')[0].strip() for l in cars)
|
||||||
print("\n", "*" * 20, len(cars), "total", "*" * 20, "\n")
|
print("\n", "*"*20, len(cars), "total", "*"*20, "\n")
|
||||||
pprint(make_count)
|
pprint(make_count)
|
||||||
|
|
|
@ -2,6 +2,3 @@
|
||||||
|
|
||||||
echo "compressing training guide images"
|
echo "compressing training guide images"
|
||||||
optipng -o7 -strip all training/* training_wide/*
|
optipng -o7 -strip all training/* training_wide/*
|
||||||
|
|
||||||
# This can sometimes provide smaller images
|
|
||||||
# mogrify -quality 100 -format jpg training_wide/* training/*
|
|
||||||
|
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.5 MiB |
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 914 KiB After Width: | Height: | Size: 688 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 947 KiB After Width: | Height: | Size: 743 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 1.5 MiB After Width: | Height: | Size: 1.1 MiB |
Before Width: | Height: | Size: 919 KiB After Width: | Height: | Size: 708 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.9 MiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 793 KiB After Width: | Height: | Size: 720 KiB |
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 894 KiB |
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.0 MiB |
Before Width: | Height: | Size: 818 KiB After Width: | Height: | Size: 718 KiB |
Before Width: | Height: | Size: 707 KiB After Width: | Height: | Size: 612 KiB |
Before Width: | Height: | Size: 871 KiB After Width: | Height: | Size: 821 KiB |
Before Width: | Height: | Size: 1.5 MiB After Width: | Height: | Size: 1.7 MiB |
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 1010 KiB After Width: | Height: | Size: 897 KiB |
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 51 KiB |
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 792 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 1.8 MiB After Width: | Height: | Size: 1.6 MiB |
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 949 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 1.6 MiB After Width: | Height: | Size: 2.1 MiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 944 KiB After Width: | Height: | Size: 821 KiB |
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.0 MiB |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.0 MiB |
Before Width: | Height: | Size: 915 KiB After Width: | Height: | Size: 794 KiB |
Before Width: | Height: | Size: 854 KiB After Width: | Height: | Size: 738 KiB |
Before Width: | Height: | Size: 1001 KiB After Width: | Height: | Size: 852 KiB |
|
@ -1,6 +1,7 @@
|
||||||
#include "selfdrive/boardd/boardd.h"
|
#include "selfdrive/boardd/boardd.h"
|
||||||
|
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
|
#include <string>
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
@ -161,7 +162,7 @@ bool safety_setter_thread(std::vector<Panda *> pandas) {
|
||||||
int safety_param;
|
int safety_param;
|
||||||
|
|
||||||
auto safety_configs = car_params.getSafetyConfigs();
|
auto safety_configs = car_params.getSafetyConfigs();
|
||||||
uint16_t alternative_experience = car_params.getAlternativeExperience();
|
uint16_t unsafe_mode = car_params.getUnsafeMode();
|
||||||
for (uint32_t i = 0; i < pandas.size(); i++) {
|
for (uint32_t i = 0; i < pandas.size(); i++) {
|
||||||
auto panda = pandas[i];
|
auto panda = pandas[i];
|
||||||
|
|
||||||
|
@ -174,8 +175,8 @@ bool safety_setter_thread(std::vector<Panda *> pandas) {
|
||||||
safety_param = 0;
|
safety_param = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGW("panda %d: setting safety model: %d, param: %d, alternative experience: %d", i, (int)safety_model, safety_param, alternative_experience);
|
LOGW("panda %d: setting safety model: %d, param: %d, unsafe mode: %d", i, (int)safety_model, safety_param, unsafe_mode);
|
||||||
panda->set_alternative_experience(alternative_experience);
|
panda->set_unsafe_mode(unsafe_mode);
|
||||||
panda->set_safety_model(safety_model, safety_param);
|
panda->set_safety_model(safety_model, safety_param);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,10 +227,17 @@ void can_send_thread(std::vector<Panda *> pandas, bool fake_send) {
|
||||||
capnp::FlatArrayMessageReader cmsg(aligned_buf.align(msg.get()));
|
capnp::FlatArrayMessageReader cmsg(aligned_buf.align(msg.get()));
|
||||||
cereal::Event::Reader event = cmsg.getRoot<cereal::Event>();
|
cereal::Event::Reader event = cmsg.getRoot<cereal::Event>();
|
||||||
|
|
||||||
|
//setenv("FRAME_ID", std::to_string(event.getLogMonoTime()).c_str(),1);
|
||||||
|
set_frame_id(event.getLogMonoTime());
|
||||||
|
LOGW(event.getLogMonoTime());
|
||||||
|
|
||||||
|
LOGTT("sendcan received", true);
|
||||||
|
|
||||||
//Dont send if older than 1 second
|
//Dont send if older than 1 second
|
||||||
if ((nanos_since_boot() - event.getLogMonoTime() < 1e9) && !fake_send) {
|
if ((nanos_since_boot() - event.getLogMonoTime() < 1e9) && !fake_send) {
|
||||||
for (const auto& panda : pandas) {
|
for (const auto& panda : pandas) {
|
||||||
panda->can_send(event.getSendcan());
|
panda->can_send(event.getSendcan());
|
||||||
|
LOGTT((std::string("sendcan sent to panda: ")+std::string(panda->usb_serial)).c_str() , true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -362,7 +370,7 @@ std::optional<bool> send_panda_states(PubMaster *pm, const std::vector<Panda *>
|
||||||
ps.setFaultStatus(cereal::PandaState::FaultStatus(health.fault_status_pkt));
|
ps.setFaultStatus(cereal::PandaState::FaultStatus(health.fault_status_pkt));
|
||||||
ps.setPowerSaveEnabled((bool)(health.power_save_enabled_pkt));
|
ps.setPowerSaveEnabled((bool)(health.power_save_enabled_pkt));
|
||||||
ps.setHeartbeatLost((bool)(health.heartbeat_lost_pkt));
|
ps.setHeartbeatLost((bool)(health.heartbeat_lost_pkt));
|
||||||
ps.setAlternativeExperience(health.alternative_experience_pkt);
|
ps.setUnsafeMode(health.unsafe_mode_pkt);
|
||||||
ps.setHarnessStatus(cereal::PandaState::HarnessStatus(health.car_harness_status_pkt));
|
ps.setHarnessStatus(cereal::PandaState::HarnessStatus(health.car_harness_status_pkt));
|
||||||
|
|
||||||
// Convert faults bitset to capnp list
|
// Convert faults bitset to capnp list
|
||||||
|
|
|
@ -251,8 +251,8 @@ void Panda::set_safety_model(cereal::CarParams::SafetyModel safety_model, int sa
|
||||||
usb_write(0xdc, (uint16_t)safety_model, safety_param);
|
usb_write(0xdc, (uint16_t)safety_model, safety_param);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panda::set_alternative_experience(uint16_t alternative_experience) {
|
void Panda::set_unsafe_mode(uint16_t unsafe_mode) {
|
||||||
usb_write(0xdf, alternative_experience, 0);
|
usb_write(0xdf, unsafe_mode, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
cereal::PandaState::PandaType Panda::get_hw_type() {
|
cereal::PandaState::PandaType Panda::get_hw_type() {
|
||||||
|
|
|
@ -74,7 +74,7 @@ class Panda {
|
||||||
// Panda functionality
|
// Panda functionality
|
||||||
cereal::PandaState::PandaType get_hw_type();
|
cereal::PandaState::PandaType get_hw_type();
|
||||||
void set_safety_model(cereal::CarParams::SafetyModel safety_model, int safety_param=0);
|
void set_safety_model(cereal::CarParams::SafetyModel safety_model, int safety_param=0);
|
||||||
void set_alternative_experience(uint16_t alternative_experience);
|
void set_unsafe_mode(uint16_t unsafe_mode);
|
||||||
void set_rtc(struct tm sys_time);
|
void set_rtc(struct tm sys_time);
|
||||||
struct tm get_rtc();
|
struct tm get_rtc();
|
||||||
void set_fan_speed(uint16_t fan_speed);
|
void set_fan_speed(uint16_t fan_speed);
|
||||||
|
|
|
@ -74,4 +74,4 @@ class TestBoarddApiMethods(unittest.TestCase):
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -52,7 +52,7 @@ public:
|
||||||
CL_CHECK(clReleaseProgram(prg_debayer));
|
CL_CHECK(clReleaseProgram(prg_debayer));
|
||||||
}
|
}
|
||||||
|
|
||||||
void queue(cl_command_queue q, cl_mem cam_buf_cl, cl_mem buf_cl, int width, int height, float gain, float black_level, cl_event *debayer_event) {
|
void queue(cl_command_queue q, cl_mem cam_buf_cl, cl_mem buf_cl, int width, int height, float gain, cl_event *debayer_event) {
|
||||||
CL_CHECK(clSetKernelArg(krnl_, 0, sizeof(cl_mem), &cam_buf_cl));
|
CL_CHECK(clSetKernelArg(krnl_, 0, sizeof(cl_mem), &cam_buf_cl));
|
||||||
CL_CHECK(clSetKernelArg(krnl_, 1, sizeof(cl_mem), &buf_cl));
|
CL_CHECK(clSetKernelArg(krnl_, 1, sizeof(cl_mem), &buf_cl));
|
||||||
|
|
||||||
|
@ -62,7 +62,6 @@ public:
|
||||||
const size_t globalWorkSize[] = {size_t(width), size_t(height)};
|
const size_t globalWorkSize[] = {size_t(width), size_t(height)};
|
||||||
const size_t localWorkSize[] = {debayer_local_worksize, debayer_local_worksize};
|
const size_t localWorkSize[] = {debayer_local_worksize, debayer_local_worksize};
|
||||||
CL_CHECK(clSetKernelArg(krnl_, 2, localMemSize, 0));
|
CL_CHECK(clSetKernelArg(krnl_, 2, localMemSize, 0));
|
||||||
CL_CHECK(clSetKernelArg(krnl_, 3, sizeof(float), &black_level));
|
|
||||||
CL_CHECK(clEnqueueNDRangeKernel(q, krnl_, 2, NULL, globalWorkSize, localWorkSize, 0, 0, debayer_event));
|
CL_CHECK(clEnqueueNDRangeKernel(q, krnl_, 2, NULL, globalWorkSize, localWorkSize, 0, 0, debayer_event));
|
||||||
} else {
|
} else {
|
||||||
if (hdr_) {
|
if (hdr_) {
|
||||||
|
@ -158,6 +157,8 @@ bool CameraBuf::acquire() {
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_frame_data = camera_bufs_metadata[cur_buf_idx];
|
cur_frame_data = camera_bufs_metadata[cur_buf_idx];
|
||||||
|
set_frame_id(cur_frame_data.frame_id);
|
||||||
|
LOGT("Start acquire camera buffer");
|
||||||
cur_rgb_buf = vipc_server->get_buffer(rgb_type);
|
cur_rgb_buf = vipc_server->get_buffer(rgb_type);
|
||||||
cl_mem camrabuf_cl = camera_bufs[cur_buf_idx].buf_cl;
|
cl_mem camrabuf_cl = camera_bufs[cur_buf_idx].buf_cl;
|
||||||
cl_event event;
|
cl_event event;
|
||||||
|
@ -166,15 +167,13 @@ bool CameraBuf::acquire() {
|
||||||
|
|
||||||
if (debayer) {
|
if (debayer) {
|
||||||
float gain = 0.0;
|
float gain = 0.0;
|
||||||
float black_level = 42.0;
|
|
||||||
#ifndef QCOM2
|
#ifndef QCOM2
|
||||||
gain = camera_state->digital_gain;
|
gain = camera_state->digital_gain;
|
||||||
if ((int)gain == 0) gain = 1.0;
|
if ((int)gain == 0) gain = 1.0;
|
||||||
#else
|
|
||||||
if (camera_state->camera_id == CAMERA_ID_IMX390) black_level = 64.0;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
debayer->queue(q, camrabuf_cl, cur_rgb_buf->buf_cl, rgb_width, rgb_height, gain, black_level, &event);
|
debayer->queue(q, camrabuf_cl, cur_rgb_buf->buf_cl, rgb_width, rgb_height, gain, &event);
|
||||||
} else {
|
} else {
|
||||||
assert(rgb_stride == camera_state->ci.frame_stride);
|
assert(rgb_stride == camera_state->ci.frame_stride);
|
||||||
CL_CHECK(clEnqueueCopyBuffer(q, camrabuf_cl, cur_rgb_buf->buf_cl, 0, 0, cur_rgb_buf->len, 0, 0, &event));
|
CL_CHECK(clEnqueueCopyBuffer(q, camrabuf_cl, cur_rgb_buf->buf_cl, 0, 0, cur_rgb_buf->len, 0, 0, &event));
|
||||||
|
@ -197,7 +196,7 @@ bool CameraBuf::acquire() {
|
||||||
cur_yuv_buf->set_frame_id(cur_frame_data.frame_id);
|
cur_yuv_buf->set_frame_id(cur_frame_data.frame_id);
|
||||||
vipc_server->send(cur_rgb_buf, &extra);
|
vipc_server->send(cur_rgb_buf, &extra);
|
||||||
vipc_server->send(cur_yuv_buf, &extra);
|
vipc_server->send(cur_yuv_buf, &extra);
|
||||||
|
LOGT("End acquire camera buffer");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,14 +377,22 @@ void *processing_thread(MultiCameraState *cameras, CameraState *cs, process_thre
|
||||||
uint32_t cnt = 0;
|
uint32_t cnt = 0;
|
||||||
while (!do_exit) {
|
while (!do_exit) {
|
||||||
if (!cs->buf.acquire()) continue;
|
if (!cs->buf.acquire()) continue;
|
||||||
|
//setenv("FRAME_ID", std::to_string(cs->buf.cur_frame_data.frame_id).c_str(),1);
|
||||||
|
set_frame_id(cs->buf.cur_frame_data.frame_id);
|
||||||
|
LOGT((std::string(thread_name)+std::string(": Start")).c_str());
|
||||||
|
|
||||||
callback(cameras, cs, cnt);
|
callback(cameras, cs, cnt);
|
||||||
|
|
||||||
|
LOGT((std::string(thread_name)+std::string(": END")).c_str());
|
||||||
|
|
||||||
if (cs == &(cameras->road_cam) && cameras->pm && cnt % 100 == 3) {
|
if (cs == &(cameras->road_cam) && cameras->pm && cnt % 100 == 3) {
|
||||||
// this takes 10ms???
|
// this takes 10ms???
|
||||||
|
LOGT((std::string(thread_name)+std::string(": Send thumbnail")).c_str());
|
||||||
publish_thumbnail(cameras->pm, &(cs->buf));
|
publish_thumbnail(cameras->pm, &(cs->buf));
|
||||||
|
LOGT((std::string(thread_name)+std::string(": Send thumbnail done")).c_str());
|
||||||
}
|
}
|
||||||
cs->buf.release();
|
cs->buf.release();
|
||||||
|
LOGT((std::string(thread_name)+std::string(": Released")).c_str());
|
||||||
++cnt;
|
++cnt;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -443,7 +450,9 @@ void common_process_driver_camera(MultiCameraState *s, CameraState *c, int cnt)
|
||||||
if (env_send_driver) {
|
if (env_send_driver) {
|
||||||
framed.setImage(get_frame_image(&c->buf));
|
framed.setImage(get_frame_image(&c->buf));
|
||||||
}
|
}
|
||||||
|
LOGT("DriverCamera: Image set");
|
||||||
s->pm->send("driverCameraState", msg);
|
s->pm->send("driverCameraState", msg);
|
||||||
|
LOGT("DriverCamera: Published");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,7 @@
|
||||||
#define CAMERA_ID_LGC920 6
|
#define CAMERA_ID_LGC920 6
|
||||||
#define CAMERA_ID_LGC615 7
|
#define CAMERA_ID_LGC615 7
|
||||||
#define CAMERA_ID_AR0231 8
|
#define CAMERA_ID_AR0231 8
|
||||||
#define CAMERA_ID_IMX390 9
|
#define CAMERA_ID_MAX 9
|
||||||
#define CAMERA_ID_MAX 10
|
|
||||||
|
|
||||||
const int UI_BUF_COUNT = 4;
|
const int UI_BUF_COUNT = 4;
|
||||||
const int YUV_BUFFER_COUNT = Hardware::EON() ? 100 : 40;
|
const int YUV_BUFFER_COUNT = Hardware::EON() ? 100 : 40;
|
||||||
|
|
|
@ -22,9 +22,6 @@
|
||||||
#include "selfdrive/common/swaglog.h"
|
#include "selfdrive/common/swaglog.h"
|
||||||
#include "selfdrive/camerad/cameras/sensor2_i2c.h"
|
#include "selfdrive/camerad/cameras/sensor2_i2c.h"
|
||||||
|
|
||||||
// For debugging:
|
|
||||||
// echo "4294967295" > /sys/module/cam_debug_util/parameters/debug_mdl
|
|
||||||
|
|
||||||
extern ExitHandler do_exit;
|
extern ExitHandler do_exit;
|
||||||
|
|
||||||
const size_t FRAME_WIDTH = 1928;
|
const size_t FRAME_WIDTH = 1928;
|
||||||
|
@ -42,14 +39,6 @@ CameraInfo cameras_supported[CAMERA_ID_MAX] = {
|
||||||
.bayer_flip = 1,
|
.bayer_flip = 1,
|
||||||
.hdr = false
|
.hdr = false
|
||||||
},
|
},
|
||||||
[CAMERA_ID_IMX390] = {
|
|
||||||
.frame_width = FRAME_WIDTH,
|
|
||||||
.frame_height = FRAME_HEIGHT,
|
|
||||||
.frame_stride = FRAME_STRIDE,
|
|
||||||
.bayer = true,
|
|
||||||
.bayer_flip = 1,
|
|
||||||
.hdr = false
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const float DC_GAIN = 2.5;
|
const float DC_GAIN = 2.5;
|
||||||
|
@ -171,15 +160,8 @@ void clear_req_queue(int fd, int32_t session_hdl, int32_t link_hdl) {
|
||||||
// ************** high level camera helpers ****************
|
// ************** high level camera helpers ****************
|
||||||
|
|
||||||
void CameraState::sensors_start() {
|
void CameraState::sensors_start() {
|
||||||
if (camera_id == CAMERA_ID_AR0231) {
|
int start_reg_len = sizeof(start_reg_array) / sizeof(struct i2c_random_wr_payload);
|
||||||
int start_reg_len = sizeof(start_reg_array_ar0231) / sizeof(struct i2c_random_wr_payload);
|
sensors_i2c(start_reg_array, start_reg_len, CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG);
|
||||||
sensors_i2c(start_reg_array_ar0231, start_reg_len, CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG, true);
|
|
||||||
} else if (camera_id == CAMERA_ID_IMX390) {
|
|
||||||
int start_reg_len = sizeof(start_reg_array_imx390) / sizeof(struct i2c_random_wr_payload);
|
|
||||||
sensors_i2c(start_reg_array_imx390, start_reg_len, CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG, false);
|
|
||||||
} else {
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CameraState::sensors_poke(int request_id) {
|
void CameraState::sensors_poke(int request_id) {
|
||||||
|
@ -199,7 +181,7 @@ void CameraState::sensors_poke(int request_id) {
|
||||||
release_fd(multi_cam_state->video0_fd, cam_packet_handle);
|
release_fd(multi_cam_state->video0_fd, cam_packet_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CameraState::sensors_i2c(struct i2c_random_wr_payload* dat, int len, int op_code, bool data_word) {
|
void CameraState::sensors_i2c(struct i2c_random_wr_payload* dat, int len, int op_code) {
|
||||||
// LOGD("sensors_i2c: %d", len);
|
// LOGD("sensors_i2c: %d", len);
|
||||||
uint32_t cam_packet_handle = 0;
|
uint32_t cam_packet_handle = 0;
|
||||||
int size = sizeof(struct cam_packet)+sizeof(struct cam_cmd_buf_desc)*1;
|
int size = sizeof(struct cam_packet)+sizeof(struct cam_cmd_buf_desc)*1;
|
||||||
|
@ -217,7 +199,7 @@ void CameraState::sensors_i2c(struct i2c_random_wr_payload* dat, int len, int op
|
||||||
i2c_random_wr->header.count = len;
|
i2c_random_wr->header.count = len;
|
||||||
i2c_random_wr->header.op_code = 1;
|
i2c_random_wr->header.op_code = 1;
|
||||||
i2c_random_wr->header.cmd_type = CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR;
|
i2c_random_wr->header.cmd_type = CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR;
|
||||||
i2c_random_wr->header.data_type = data_word ? CAMERA_SENSOR_I2C_TYPE_WORD : CAMERA_SENSOR_I2C_TYPE_BYTE;
|
i2c_random_wr->header.data_type = CAMERA_SENSOR_I2C_TYPE_WORD;
|
||||||
i2c_random_wr->header.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD;
|
i2c_random_wr->header.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD;
|
||||||
memcpy(i2c_random_wr->random_wr_payload, dat, len*sizeof(struct i2c_random_wr_payload));
|
memcpy(i2c_random_wr->random_wr_payload, dat, len*sizeof(struct i2c_random_wr_payload));
|
||||||
|
|
||||||
|
@ -238,7 +220,7 @@ static cam_cmd_power *power_set_wait(cam_cmd_power *power, int16_t delay_ms) {
|
||||||
return (struct cam_cmd_power *)(unconditional_wait + 1);
|
return (struct cam_cmd_power *)(unconditional_wait + 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
int CameraState::sensors_init() {
|
void CameraState::sensors_init() {
|
||||||
int video0_fd = multi_cam_state->video0_fd;
|
int video0_fd = multi_cam_state->video0_fd;
|
||||||
uint32_t cam_packet_handle = 0;
|
uint32_t cam_packet_handle = 0;
|
||||||
int size = sizeof(struct cam_packet)+sizeof(struct cam_cmd_buf_desc)*2;
|
int size = sizeof(struct cam_packet)+sizeof(struct cam_cmd_buf_desc)*2;
|
||||||
|
@ -257,17 +239,17 @@ int CameraState::sensors_init() {
|
||||||
switch (camera_num) {
|
switch (camera_num) {
|
||||||
case 0:
|
case 0:
|
||||||
// port 0
|
// port 0
|
||||||
i2c_info->slave_addr = (camera_id == CAMERA_ID_AR0231) ? 0x20 : 0x34;
|
i2c_info->slave_addr = 0x20;
|
||||||
probe->camera_id = 0;
|
probe->camera_id = 0;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
// port 1
|
// port 1
|
||||||
i2c_info->slave_addr = (camera_id == CAMERA_ID_AR0231) ? 0x30 : 0x36;
|
i2c_info->slave_addr = 0x30;
|
||||||
probe->camera_id = 1;
|
probe->camera_id = 1;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
// port 2
|
// port 2
|
||||||
i2c_info->slave_addr = (camera_id == CAMERA_ID_AR0231) ? 0x20 : 0x34;
|
i2c_info->slave_addr = 0x20;
|
||||||
probe->camera_id = 2;
|
probe->camera_id = 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -281,15 +263,8 @@ int CameraState::sensors_init() {
|
||||||
probe->addr_type = CAMERA_SENSOR_I2C_TYPE_WORD;
|
probe->addr_type = CAMERA_SENSOR_I2C_TYPE_WORD;
|
||||||
probe->op_code = 3; // don't care?
|
probe->op_code = 3; // don't care?
|
||||||
probe->cmd_type = CAMERA_SENSOR_CMD_TYPE_PROBE;
|
probe->cmd_type = CAMERA_SENSOR_CMD_TYPE_PROBE;
|
||||||
if (camera_id == CAMERA_ID_AR0231) {
|
probe->reg_addr = 0x3000; //0x300a; //0x300b;
|
||||||
probe->reg_addr = 0x3000;
|
probe->expected_data = 0x354; //0x7750; //0x885a;
|
||||||
probe->expected_data = 0x354;
|
|
||||||
} else if (camera_id == CAMERA_ID_IMX390) {
|
|
||||||
probe->reg_addr = 0x330;
|
|
||||||
probe->expected_data = 0x1538;
|
|
||||||
} else {
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
probe->data_mask = 0;
|
probe->data_mask = 0;
|
||||||
|
|
||||||
//buf_desc[1].size = buf_desc[1].length = 148;
|
//buf_desc[1].size = buf_desc[1].length = 148;
|
||||||
|
@ -318,7 +293,7 @@ int CameraState::sensors_init() {
|
||||||
power->count = 1;
|
power->count = 1;
|
||||||
power->cmd_type = CAMERA_SENSOR_CMD_TYPE_PWR_UP;
|
power->cmd_type = CAMERA_SENSOR_CMD_TYPE_PWR_UP;
|
||||||
power->power_settings[0].power_seq_type = 0;
|
power->power_settings[0].power_seq_type = 0;
|
||||||
power->power_settings[0].config_val_low = (camera_id == CAMERA_ID_AR0231) ? 19200000 : 24000000; //Hz
|
power->power_settings[0].config_val_low = 19200000; //Hz
|
||||||
power = power_set_wait(power, 10);
|
power = power_set_wait(power, 10);
|
||||||
|
|
||||||
// 8,1 is this reset?
|
// 8,1 is this reset?
|
||||||
|
@ -366,6 +341,7 @@ int CameraState::sensors_init() {
|
||||||
|
|
||||||
LOGD("probing the sensor");
|
LOGD("probing the sensor");
|
||||||
int ret = do_cam_control(sensor_fd, CAM_SENSOR_PROBE_CMD, (void *)(uintptr_t)cam_packet_handle, 0);
|
int ret = do_cam_control(sensor_fd, CAM_SENSOR_PROBE_CMD, (void *)(uintptr_t)cam_packet_handle, 0);
|
||||||
|
assert(ret == 0);
|
||||||
|
|
||||||
munmap(i2c_info, buf_desc[0].size);
|
munmap(i2c_info, buf_desc[0].size);
|
||||||
release_fd(video0_fd, buf_desc[0].mem_handle);
|
release_fd(video0_fd, buf_desc[0].mem_handle);
|
||||||
|
@ -373,8 +349,6 @@ int CameraState::sensors_init() {
|
||||||
release_fd(video0_fd, buf_desc[1].mem_handle);
|
release_fd(video0_fd, buf_desc[1].mem_handle);
|
||||||
munmap(pkt, size);
|
munmap(pkt, size);
|
||||||
release_fd(video0_fd, cam_packet_handle);
|
release_fd(video0_fd, cam_packet_handle);
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CameraState::config_isp(int io_mem_handle, int fence, int request_id, int buf0_mem_handle, int buf0_offset) {
|
void CameraState::config_isp(int io_mem_handle, int fence, int request_id, int buf0_mem_handle, int buf0_offset) {
|
||||||
|
@ -587,10 +561,9 @@ void CameraState::enqueue_req_multi(int start, int n, bool dp) {
|
||||||
|
|
||||||
// ******************* camera *******************
|
// ******************* camera *******************
|
||||||
|
|
||||||
void CameraState::camera_init(MultiCameraState *multi_cam_state_, VisionIpcServer * v, int camera_id_, int camera_num_, unsigned int fps, cl_device_id device_id, cl_context ctx, VisionStreamType rgb_type, VisionStreamType yuv_type) {
|
void CameraState::camera_init(MultiCameraState *multi_cam_state_, VisionIpcServer * v, int camera_id, int camera_num_, unsigned int fps, cl_device_id device_id, cl_context ctx, VisionStreamType rgb_type, VisionStreamType yuv_type) {
|
||||||
LOGD("camera init %d", camera_num);
|
LOGD("camera init %d", camera_num);
|
||||||
multi_cam_state = multi_cam_state_;
|
multi_cam_state = multi_cam_state_;
|
||||||
camera_id = camera_id_;
|
|
||||||
assert(camera_id < std::size(cameras_supported));
|
assert(camera_id < std::size(cameras_supported));
|
||||||
ci = cameras_supported[camera_id];
|
ci = cameras_supported[camera_id];
|
||||||
assert(ci.frame_width != 0);
|
assert(ci.frame_width != 0);
|
||||||
|
@ -613,24 +586,17 @@ void CameraState::camera_init(MultiCameraState *multi_cam_state_, VisionIpcServe
|
||||||
}
|
}
|
||||||
|
|
||||||
void CameraState::camera_open() {
|
void CameraState::camera_open() {
|
||||||
int ret;
|
|
||||||
sensor_fd = open_v4l_by_name_and_index("cam-sensor-driver", camera_num);
|
sensor_fd = open_v4l_by_name_and_index("cam-sensor-driver", camera_num);
|
||||||
assert(sensor_fd >= 0);
|
assert(sensor_fd >= 0);
|
||||||
LOGD("opened sensor for %d", camera_num);
|
LOGD("opened sensor for %d", camera_num);
|
||||||
|
|
||||||
// probe the sensor
|
// probe the sensor
|
||||||
LOGD("-- Probing sensor %d", camera_num);
|
LOGD("-- Probing sensor %d", camera_num);
|
||||||
ret = sensors_init();
|
sensors_init();
|
||||||
if (ret != 0) {
|
|
||||||
LOGD("AR0231 init failed, trying IMX390");
|
|
||||||
camera_id = CAMERA_ID_IMX390;
|
|
||||||
ret = sensors_init();
|
|
||||||
}
|
|
||||||
assert(ret == 0);
|
|
||||||
|
|
||||||
// create session
|
// create session
|
||||||
struct cam_req_mgr_session_info session_info = {};
|
struct cam_req_mgr_session_info session_info = {};
|
||||||
ret = do_cam_control(multi_cam_state->video0_fd, CAM_REQ_MGR_CREATE_SESSION, &session_info, sizeof(session_info));
|
int ret = do_cam_control(multi_cam_state->video0_fd, CAM_REQ_MGR_CREATE_SESSION, &session_info, sizeof(session_info));
|
||||||
LOGD("get session: %d 0x%X", ret, session_info.session_hdl);
|
LOGD("get session: %d 0x%X", ret, session_info.session_hdl);
|
||||||
session_handle = session_info.session_hdl;
|
session_handle = session_info.session_hdl;
|
||||||
|
|
||||||
|
@ -709,13 +675,10 @@ void CameraState::camera_open() {
|
||||||
config_isp(0, 0, 1, buf0_handle, 0);
|
config_isp(0, 0, 1, buf0_handle, 0);
|
||||||
|
|
||||||
LOG("-- Configuring sensor");
|
LOG("-- Configuring sensor");
|
||||||
if (camera_id == CAMERA_ID_AR0231) {
|
sensors_i2c(init_array_ar0231, std::size(init_array_ar0231), CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG);
|
||||||
sensors_i2c(init_array_ar0231, std::size(init_array_ar0231), CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG, true);
|
//sensors_i2c(start_reg_array, std::size(start_reg_array), CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMON);
|
||||||
} else if (camera_id == CAMERA_ID_IMX390) {
|
//sensors_i2c(stop_reg_array, std::size(stop_reg_array), CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMOFF);
|
||||||
sensors_i2c(init_array_imx390, std::size(init_array_imx390), CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG, false);
|
|
||||||
} else {
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// config csiphy
|
// config csiphy
|
||||||
LOG("-- Config CSI PHY");
|
LOG("-- Config CSI PHY");
|
||||||
|
@ -1045,28 +1008,14 @@ void CameraState::set_camera_exposure(float grey_frac) {
|
||||||
}
|
}
|
||||||
// LOGE("ae - camera %d, cur_t %.5f, sof %.5f, dt %.5f", camera_num, 1e-9 * nanos_since_boot(), 1e-9 * buf.cur_frame_data.timestamp_sof, 1e-9 * (nanos_since_boot() - buf.cur_frame_data.timestamp_sof));
|
// LOGE("ae - camera %d, cur_t %.5f, sof %.5f, dt %.5f", camera_num, 1e-9 * nanos_since_boot(), 1e-9 * buf.cur_frame_data.timestamp_sof, 1e-9 * (nanos_since_boot() - buf.cur_frame_data.timestamp_sof));
|
||||||
|
|
||||||
if (camera_id == CAMERA_ID_AR0231) {
|
uint16_t analog_gain_reg = 0xFF00 | (new_g << 4) | new_g;
|
||||||
uint16_t analog_gain_reg = 0xFF00 | (new_g << 4) | new_g;
|
struct i2c_random_wr_payload exp_reg_array[] = {
|
||||||
struct i2c_random_wr_payload exp_reg_array[] = {
|
{0x3366, analog_gain_reg},
|
||||||
{0x3366, analog_gain_reg},
|
{0x3362, (uint16_t)(dc_gain_enabled ? 0x1 : 0x0)},
|
||||||
{0x3362, (uint16_t)(dc_gain_enabled ? 0x1 : 0x0)},
|
{0x3012, (uint16_t)exposure_time},
|
||||||
{0x3012, (uint16_t)exposure_time},
|
};
|
||||||
};
|
sensors_i2c(exp_reg_array, sizeof(exp_reg_array)/sizeof(struct i2c_random_wr_payload),
|
||||||
sensors_i2c(exp_reg_array, sizeof(exp_reg_array)/sizeof(struct i2c_random_wr_payload), CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG, true);
|
CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG);
|
||||||
} else if (camera_id == CAMERA_ID_IMX390) {
|
|
||||||
// if gain is sub 1, we have to use exposure to mimic sub 1 gains
|
|
||||||
uint32_t real_exposure_time = (gain < 1.0) ? (exposure_time*gain) : exposure_time;
|
|
||||||
// invert real_exposure_time, max exposure is 2
|
|
||||||
real_exposure_time = (exposure_time >= 0x7cf) ? 2 : (0x7cf - exposure_time);
|
|
||||||
uint32_t real_gain = int((10*log10(fmax(1.0, gain)))/0.3);
|
|
||||||
//printf("%d expose: %d gain: %f = %d\n", camera_num, exposure_time, gain, real_gain);
|
|
||||||
struct i2c_random_wr_payload exp_reg_array[] = {
|
|
||||||
{0x000c, real_exposure_time&0xFF}, {0x000d, real_exposure_time>>8},
|
|
||||||
{0x0010, real_exposure_time&0xFF}, {0x0011, real_exposure_time>>8},
|
|
||||||
{0x0018, real_gain&0xFF}, {0x0019, real_gain>>8},
|
|
||||||
};
|
|
||||||
sensors_i2c(exp_reg_array, sizeof(exp_reg_array)/sizeof(struct i2c_random_wr_payload), CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG, false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void camera_autoexposure(CameraState *s, float grey_frac) {
|
void camera_autoexposure(CameraState *s, float grey_frac) {
|
||||||
|
@ -1083,10 +1032,13 @@ void process_road_camera(MultiCameraState *s, CameraState *c, int cnt) {
|
||||||
if ((c == &s->road_cam && env_send_road) || (c == &s->wide_road_cam && env_send_wide_road)) {
|
if ((c == &s->road_cam && env_send_road) || (c == &s->wide_road_cam && env_send_wide_road)) {
|
||||||
framed.setImage(get_frame_image(b));
|
framed.setImage(get_frame_image(b));
|
||||||
}
|
}
|
||||||
|
LOGT((std::string(c == &s->road_cam ? "RoadCamera" : "WideRoadCamera")+std::string(": Image set")).c_str());
|
||||||
if (c == &s->road_cam) {
|
if (c == &s->road_cam) {
|
||||||
framed.setTransform(b->yuv_transform.v);
|
framed.setTransform(b->yuv_transform.v);
|
||||||
|
LOGT((std::string(c == &s->road_cam ? "RoadCamera" : "WideRoadCamera")+std::string(": Transformed")).c_str());
|
||||||
}
|
}
|
||||||
s->pm->send(c == &s->road_cam ? "roadCameraState" : "wideRoadCameraState", msg);
|
s->pm->send(c == &s->road_cam ? "roadCameraState" : "wideRoadCameraState", msg);
|
||||||
|
LOGT((std::string(c == &s->road_cam ? "RoadCamera" : "WideRoadCamera")+std::string(": Published")).c_str());
|
||||||
|
|
||||||
const auto [x, y, w, h] = (c == &s->wide_road_cam) ? std::tuple(96, 250, 1734, 524) : std::tuple(96, 160, 1734, 986);
|
const auto [x, y, w, h] = (c == &s->wide_road_cam) ? std::tuple(96, 250, 1734, 524) : std::tuple(96, 160, 1734, 986);
|
||||||
const int skip = 2;
|
const int skip = 2;
|
||||||
|
|
|
@ -40,8 +40,8 @@ public:
|
||||||
|
|
||||||
void sensors_start();
|
void sensors_start();
|
||||||
void sensors_poke(int request_id);
|
void sensors_poke(int request_id);
|
||||||
void sensors_i2c(struct i2c_random_wr_payload* dat, int len, int op_code, bool data_word);
|
void sensors_i2c(struct i2c_random_wr_payload* dat, int len, int op_code);
|
||||||
int sensors_init();
|
void sensors_init();
|
||||||
|
|
||||||
void camera_open();
|
void camera_open();
|
||||||
void camera_init(MultiCameraState *multi_cam_state, VisionIpcServer * v, int camera_id, int camera_num, unsigned int fps, cl_device_id device_id, cl_context ctx, VisionStreamType rgb_type, VisionStreamType yuv_type);
|
void camera_init(MultiCameraState *multi_cam_state, VisionIpcServer * v, int camera_id, int camera_num, unsigned int fps, cl_device_id device_id, cl_context ctx, VisionStreamType rgb_type, VisionStreamType yuv_type);
|
||||||
|
@ -62,7 +62,6 @@ public:
|
||||||
int frame_id_last;
|
int frame_id_last;
|
||||||
int idx_offset;
|
int idx_offset;
|
||||||
bool skipped;
|
bool skipped;
|
||||||
int camera_id;
|
|
||||||
|
|
||||||
CameraBuf buf;
|
CameraBuf buf;
|
||||||
};
|
};
|
||||||
|
@ -74,6 +73,7 @@ typedef struct MultiCameraState {
|
||||||
int device_iommu;
|
int device_iommu;
|
||||||
int cdm_iommu;
|
int cdm_iommu;
|
||||||
|
|
||||||
|
|
||||||
CameraState road_cam;
|
CameraState road_cam;
|
||||||
CameraState wide_road_cam;
|
CameraState wide_road_cam;
|
||||||
CameraState driver_cam;
|
CameraState driver_cam;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
||||||
|
|
||||||
|
const half black_level = 42.0;
|
||||||
|
|
||||||
const __constant half3 color_correction[3] = {
|
const __constant half3 color_correction[3] = {
|
||||||
// post wb CCM
|
// post wb CCM
|
||||||
(half3)(1.82717181, -0.31231438, 0.07307673),
|
(half3)(1.82717181, -0.31231438, 0.07307673),
|
||||||
|
@ -37,7 +39,7 @@ half3 color_correct(half3 rgb) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline half val_from_10(const uchar * source, int gx, int gy, half black_level) {
|
half val_from_10(const uchar * source, int gx, int gy) {
|
||||||
// parse 12bit
|
// parse 12bit
|
||||||
int start = gy * FRAME_STRIDE + (3 * (gx / 2));
|
int start = gy * FRAME_STRIDE + (3 * (gx / 2));
|
||||||
int offset = gx % 2;
|
int offset = gx % 2;
|
||||||
|
@ -47,7 +49,7 @@ inline half val_from_10(const uchar * source, int gx, int gy, half black_level)
|
||||||
|
|
||||||
// normalize
|
// normalize
|
||||||
pv = max(0.0h, pv - black_level);
|
pv = max(0.0h, pv - black_level);
|
||||||
pv /= (1024.0f - black_level);
|
pv *= 0.00101833h; // /= (1024.0f - black_level);
|
||||||
|
|
||||||
// correct vignetting
|
// correct vignetting
|
||||||
if (CAM_NUM == 1) { // fcamera
|
if (CAM_NUM == 1) { // fcamera
|
||||||
|
@ -87,8 +89,7 @@ half phi(half x) {
|
||||||
|
|
||||||
__kernel void debayer10(const __global uchar * in,
|
__kernel void debayer10(const __global uchar * in,
|
||||||
__global uchar * out,
|
__global uchar * out,
|
||||||
__local half * cached,
|
__local half * cached
|
||||||
float black_level
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
const int x_global = get_global_id(0);
|
const int x_global = get_global_id(0);
|
||||||
|
@ -101,7 +102,7 @@ __kernel void debayer10(const __global uchar * in,
|
||||||
|
|
||||||
int out_idx = 3 * x_global + 3 * y_global * RGB_WIDTH;
|
int out_idx = 3 * x_global + 3 * y_global * RGB_WIDTH;
|
||||||
|
|
||||||
half pv = val_from_10(in, x_global, y_global, black_level);
|
half pv = val_from_10(in, x_global, y_global);
|
||||||
cached[localOffset] = pv;
|
cached[localOffset] = pv;
|
||||||
|
|
||||||
// don't care
|
// don't care
|
||||||
|
@ -117,22 +118,22 @@ __kernel void debayer10(const __global uchar * in,
|
||||||
if (x_local < 1) {
|
if (x_local < 1) {
|
||||||
localColOffset = x_local;
|
localColOffset = x_local;
|
||||||
globalColOffset = -1;
|
globalColOffset = -1;
|
||||||
cached[(y_local + 1) * localRowLen + x_local] = val_from_10(in, x_global-1, y_global, black_level);
|
cached[(y_local + 1) * localRowLen + x_local] = val_from_10(in, x_global-1, y_global);
|
||||||
} else if (x_local >= get_local_size(0) - 1) {
|
} else if (x_local >= get_local_size(0) - 1) {
|
||||||
localColOffset = x_local + 2;
|
localColOffset = x_local + 2;
|
||||||
globalColOffset = 1;
|
globalColOffset = 1;
|
||||||
cached[localOffset + 1] = val_from_10(in, x_global+1, y_global, black_level);
|
cached[localOffset + 1] = val_from_10(in, x_global+1, y_global);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (y_local < 1) {
|
if (y_local < 1) {
|
||||||
cached[y_local * localRowLen + x_local + 1] = val_from_10(in, x_global, y_global-1, black_level);
|
cached[y_local * localRowLen + x_local + 1] = val_from_10(in, x_global, y_global-1);
|
||||||
if (localColOffset != -1) {
|
if (localColOffset != -1) {
|
||||||
cached[y_local * localRowLen + localColOffset] = val_from_10(in, x_global+globalColOffset, y_global-1, black_level);
|
cached[y_local * localRowLen + localColOffset] = val_from_10(in, x_global+globalColOffset, y_global-1);
|
||||||
}
|
}
|
||||||
} else if (y_local >= get_local_size(1) - 1) {
|
} else if (y_local >= get_local_size(1) - 1) {
|
||||||
cached[(y_local + 2) * localRowLen + x_local + 1] = val_from_10(in, x_global, y_global+1, black_level);
|
cached[(y_local + 2) * localRowLen + x_local + 1] = val_from_10(in, x_global, y_global+1);
|
||||||
if (localColOffset != -1) {
|
if (localColOffset != -1) {
|
||||||
cached[(y_local + 2) * localRowLen + localColOffset] = val_from_10(in, x_global+globalColOffset, y_global+1, black_level);
|
cached[(y_local + 2) * localRowLen + localColOffset] = val_from_10(in, x_global+globalColOffset, y_global+1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,49 +1,5 @@
|
||||||
struct i2c_random_wr_payload start_reg_array_ar0231[] = {{0x301A, 0x91C}};
|
struct i2c_random_wr_payload start_reg_array[] = {{0x301A, 0x91C}};
|
||||||
struct i2c_random_wr_payload stop_reg_array_ar0231[] = {{0x301A, 0x918}};
|
struct i2c_random_wr_payload stop_reg_array[] = {{0x301A, 0x918}};
|
||||||
struct i2c_random_wr_payload start_reg_array_imx390[] = {{0x0, 0}};
|
|
||||||
struct i2c_random_wr_payload stop_reg_array_imx390[] = {{0x0, 1}};
|
|
||||||
|
|
||||||
struct i2c_random_wr_payload init_array_imx390[] = {
|
|
||||||
{0x2008, 0xd0}, {0x2009, 0x07}, {0x200a, 0x00}, // MODE_VMAX = time between frames
|
|
||||||
{0x200C, 0xe4}, {0x200D, 0x0c}, // MODE_HMAX
|
|
||||||
|
|
||||||
// crop
|
|
||||||
{0x3410, 0x88}, {0x3411, 0x7}, // CROP_H_SIZE
|
|
||||||
{0x3418, 0xb8}, {0x3419, 0x4}, // CROP_V_SIZE
|
|
||||||
{0x0078, 1}, {0x03c0, 1},
|
|
||||||
|
|
||||||
// external trigger (off)
|
|
||||||
// while images still come in, they are blank with this
|
|
||||||
{0x3650, 0}, // CU_MODE
|
|
||||||
|
|
||||||
// exposure
|
|
||||||
{0x000c, 0xc0}, {0x000d, 0x07},
|
|
||||||
{0x0010, 0xc0}, {0x0011, 0x07},
|
|
||||||
|
|
||||||
// WUXGA mode
|
|
||||||
// not in datasheet, from https://github.com/bogsen/STLinux-Kernel/blob/master/drivers/media/platform/tegra/imx185.c
|
|
||||||
{0x0086, 0xc4}, {0x0087, 0xff}, // WND_SHIFT_V = -60
|
|
||||||
{0x03c6, 0xc4}, {0x03c7, 0xff}, // SM_WND_SHIFT_V_APL = -60
|
|
||||||
|
|
||||||
{0x201c, 0xe1}, {0x201d, 0x12}, // image read amount
|
|
||||||
{0x21ee, 0xc4}, {0x21ef, 0x04}, // image send amount (1220 is the end)
|
|
||||||
{0x21f0, 0xc4}, {0x21f1, 0x04}, // image processing amount
|
|
||||||
|
|
||||||
// disable a bunch of errors causing blanking
|
|
||||||
{0x0390, 0x00}, {0x0391, 0x00}, {0x0392, 0x00},
|
|
||||||
|
|
||||||
// flip bayer
|
|
||||||
{0x2D64, 0x64 + 2},
|
|
||||||
|
|
||||||
// color correction
|
|
||||||
{0x0030, 0xf8}, {0x0031, 0x00}, // red gain
|
|
||||||
{0x0032, 0x9a}, {0x0033, 0x00}, // gr gain
|
|
||||||
{0x0034, 0x9a}, {0x0035, 0x00}, // gb gain
|
|
||||||
{0x0036, 0x22}, {0x0037, 0x01}, // blue gain
|
|
||||||
|
|
||||||
// hdr enable (noise with this on for now)
|
|
||||||
{0x00f9, 0}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct i2c_random_wr_payload init_array_ar0231[] = {
|
struct i2c_random_wr_payload init_array_ar0231[] = {
|
||||||
{0x301A, 0x0018}, // RESET_REGISTER
|
{0x301A, 0x0018}, // RESET_REGISTER
|
||||||
|
|
|
@ -24,9 +24,9 @@ if __name__ == "__main__":
|
||||||
lr = list(LogReader(path))
|
lr = list(LogReader(path))
|
||||||
|
|
||||||
for msg in tqdm(lr):
|
for msg in tqdm(lr):
|
||||||
if msg.which() == 'thumbnail':
|
if msg.which() == 'thumbnail':
|
||||||
with open(os.path.join(out_path, f"{msg.thumbnail.frameId}.jpg"), 'wb') as f:
|
with open(os.path.join(out_path, f"{msg.thumbnail.frameId}.jpg"), 'wb') as f:
|
||||||
f.write(msg.thumbnail.thumbnail)
|
f.write(msg.thumbnail.thumbnail)
|
||||||
elif msg.which() == 'navThumbnail':
|
elif msg.which() == 'navThumbnail':
|
||||||
with open(os.path.join(out_path, f"nav_{msg.navThumbnail.frameId}.jpg"), 'wb') as f:
|
with open(os.path.join(out_path, f"nav_{msg.navThumbnail.frameId}.jpg"), 'wb') as f:
|
||||||
f.write(msg.navThumbnail.thumbnail)
|
f.write(msg.navThumbnail.thumbnail)
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
{% set footnote_tag = '[<sup>{}</sup>](#Footnotes)' -%}
|
|
||||||
{% set star_icon = '<a href="#"><img valign="top" src="assets/icon-star-{}.svg" width="22" /></a>' -%}
|
|
||||||
|
|
||||||
# Supported Cars
|
|
||||||
|
|
||||||
A supported vehicle is one that just works when you install a comma device. Every car performs differently with openpilot, but all supported cars should provide a better experience than any stock system.
|
|
||||||
|
|
||||||
Cars are organized into three tiers:
|
|
||||||
|
|
||||||
{% for tier in tiers %}
|
|
||||||
- {{tier.name.title()}} - {{tier.value}}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
How We Rate The Cars
|
|
||||||
---
|
|
||||||
|
|
||||||
### openpilot Adaptive Cruise Control (ACC)
|
|
||||||
- {{star_icon.format(Star.FULL.value)}} - openpilot is able to control the gas and brakes.
|
|
||||||
- {{star_icon.format(Star.HALF.value)}} - openpilot is able to control the gas and brakes with some restrictions.
|
|
||||||
- {{star_icon.format(Star.EMPTY.value)}} - The gas and brakes are controlled by the car's stock Adaptive Cruise Control (ACC) system.
|
|
||||||
|
|
||||||
### Stop and Go
|
|
||||||
- {{star_icon.format(Star.FULL.value)}} - Adaptive Cruise Control (ACC) operates down to 0 mph.
|
|
||||||
- {{star_icon.format(Star.EMPTY.value)}} - Adaptive Cruise Control (ACC) available only above certain speeds. See your car's manual for the minimum speed.
|
|
||||||
|
|
||||||
### Steer to 0
|
|
||||||
- {{star_icon.format(Star.FULL.value)}} - openpilot can control the steering wheel down to 0 mph.
|
|
||||||
- {{star_icon.format(Star.EMPTY.value)}} - No steering control below certain speeds.
|
|
||||||
|
|
||||||
### Steering Torque
|
|
||||||
- {{star_icon.format(Star.FULL.value)}} - Car has enough steering torque for comfortable highway driving.
|
|
||||||
- {{star_icon.format(Star.EMPTY.value)}} - Limited ability to make turns.
|
|
||||||
|
|
||||||
### Actively Maintained
|
|
||||||
- {{star_icon.format(Star.FULL.value)}} - Mainline software support, harness hardware sold by comma, lots of users, primary development target.
|
|
||||||
- {{star_icon.format(Star.EMPTY.value)}} - Low user count, community maintained, harness hardware not sold by comma.
|
|
||||||
|
|
||||||
**All supported cars can move between the tiers as support changes.**
|
|
||||||
|
|
||||||
{% for tier, cars in tiers.items() %}
|
|
||||||
## {{tier.name.title()}} Cars
|
|
||||||
|
|
||||||
|{{Column | map(attribute='value') | join('|')}}|
|
|
||||||
|---|---|---|:---:|:---:|:---:|:---:|:---:|
|
|
||||||
{% for car_info in cars %}
|
|
||||||
|{% for column in Column %}{{car_info.get_column(column, star_icon, footnote_tag)}}|{% endfor %}
|
|
||||||
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
## Footnotes
|
|
||||||
{% for footnote in footnotes %}
|
|
||||||
<sup>{{loop.index}}</sup>{{footnote}} <br />
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
## Community Maintained Cars
|
|
||||||
Although they're not upstream, the community has openpilot running on other makes and models. See the 'Community Supported Models' section of each make [on our wiki](https://wiki.comma.ai/).
|
|
|
@ -1,6 +1,4 @@
|
||||||
import os
|
import os
|
||||||
from typing import Any, Dict, List
|
|
||||||
|
|
||||||
from common.params import Params
|
from common.params import Params
|
||||||
from common.basedir import BASEDIR
|
from common.basedir import BASEDIR
|
||||||
from selfdrive.version import is_comma_remote, is_tested_branch
|
from selfdrive.version import is_comma_remote, is_tested_branch
|
||||||
|
@ -59,25 +57,19 @@ def load_interfaces(brand_names):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def get_interface_attr(attr: str) -> Dict[str, Any]:
|
def _get_interface_names():
|
||||||
# returns given attribute from each interface
|
# read all the folders in selfdrive/car and return a dict where:
|
||||||
|
# - keys are all the car names that which we have an interface for
|
||||||
|
# - values are lists of spefic car models for a given car
|
||||||
brand_names = {}
|
brand_names = {}
|
||||||
for car_folder in sorted([x[0] for x in os.walk(BASEDIR + '/selfdrive/car')]):
|
for car_folder in [x[0] for x in os.walk(BASEDIR + '/selfdrive/car')]:
|
||||||
try:
|
try:
|
||||||
brand_name = car_folder.split('/')[-1]
|
brand_name = car_folder.split('/')[-1]
|
||||||
attr_data = getattr(__import__(f'selfdrive.car.{brand_name}.values', fromlist=[attr]), attr, None)
|
model_names = __import__(f'selfdrive.car.{brand_name}.values', fromlist=['CAR']).CAR
|
||||||
brand_names[brand_name] = attr_data
|
model_names = [getattr(model_names, c) for c in model_names.__dict__.keys() if not c.startswith("__")]
|
||||||
|
brand_names[brand_name] = model_names
|
||||||
except (ImportError, OSError):
|
except (ImportError, OSError):
|
||||||
pass
|
pass
|
||||||
return brand_names
|
|
||||||
|
|
||||||
|
|
||||||
def _get_interface_names() -> Dict[str, List[str]]:
|
|
||||||
# returns a dict of brand name and its respective models
|
|
||||||
brand_names = {}
|
|
||||||
for brand_name, model_names in get_interface_attr("CAR").items():
|
|
||||||
model_names = [getattr(model_names, c) for c in model_names.__dict__.keys() if not c.startswith("__")]
|
|
||||||
brand_names[brand_name] = model_names
|
|
||||||
|
|
||||||
return brand_names
|
return brand_names
|
||||||
|
|
||||||
|
@ -181,13 +173,11 @@ def get_car(logcan, sendcan):
|
||||||
cloudlog.warning("car doesn't match any fingerprints: %r", fingerprints)
|
cloudlog.warning("car doesn't match any fingerprints: %r", fingerprints)
|
||||||
candidate = "mock"
|
candidate = "mock"
|
||||||
|
|
||||||
disable_radar = Params().get_bool("DisableRadar")
|
|
||||||
|
|
||||||
CarInterface, CarController, CarState = interfaces[candidate]
|
CarInterface, CarController, CarState = interfaces[candidate]
|
||||||
CP = CarInterface.get_params(candidate, fingerprints, car_fw, disable_radar)
|
car_params = CarInterface.get_params(candidate, fingerprints, car_fw)
|
||||||
CP.carVin = vin
|
car_params.carVin = vin
|
||||||
CP.carFw = car_fw
|
car_params.carFw = car_fw
|
||||||
CP.fingerprintSource = source
|
car_params.fingerprintSource = source
|
||||||
CP.fuzzyFingerprint = not exact_match
|
car_params.fuzzyFingerprint = not exact_match
|
||||||
|
|
||||||
return CarInterface(CP, CarController, CarState), CP
|
return CarInterface(car_params, CarController, CarState), car_params
|
||||||
|
|
|
@ -7,7 +7,6 @@ from opendbc.can.packer import CANPacker
|
||||||
|
|
||||||
class CarController():
|
class CarController():
|
||||||
def __init__(self, dbc_name, CP, VM):
|
def __init__(self, dbc_name, CP, VM):
|
||||||
self.CP = CP
|
|
||||||
self.apply_steer_last = 0
|
self.apply_steer_last = 0
|
||||||
self.ccframe = 0
|
self.ccframe = 0
|
||||||
self.prev_frame = -1
|
self.prev_frame = -1
|
||||||
|
@ -30,11 +29,11 @@ class CarController():
|
||||||
CS.out.steeringTorqueEps, CarControllerParams)
|
CS.out.steeringTorqueEps, CarControllerParams)
|
||||||
self.steer_rate_limited = new_steer != apply_steer
|
self.steer_rate_limited = new_steer != apply_steer
|
||||||
|
|
||||||
moving_fast = CS.out.vEgo > self.CP.minSteerSpeed # for status message
|
moving_fast = CS.out.vEgo > CS.CP.minSteerSpeed # for status message
|
||||||
if CS.out.vEgo > (self.CP.minSteerSpeed - 0.5): # for command high bit
|
if CS.out.vEgo > (CS.CP.minSteerSpeed - 0.5): # for command high bit
|
||||||
self.gone_fast_yet = True
|
self.gone_fast_yet = True
|
||||||
elif self.car_fingerprint in (CAR.PACIFICA_2019_HYBRID, CAR.PACIFICA_2020, CAR.JEEP_CHEROKEE_2019):
|
elif self.car_fingerprint in (CAR.PACIFICA_2019_HYBRID, CAR.PACIFICA_2020, CAR.JEEP_CHEROKEE_2019):
|
||||||
if CS.out.vEgo < (self.CP.minSteerSpeed - 3.0):
|
if CS.out.vEgo < (CS.CP.minSteerSpeed - 3.0):
|
||||||
self.gone_fast_yet = False # < 14.5m/s stock turns off this bit, but fine down to 13.5
|
self.gone_fast_yet = False # < 14.5m/s stock turns off this bit, but fine down to 13.5
|
||||||
lkas_active = moving_fast and enabled
|
lkas_active = moving_fast and enabled
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ from selfdrive.car.interfaces import CarInterfaceBase
|
||||||
|
|
||||||
class CarInterface(CarInterfaceBase):
|
class CarInterface(CarInterfaceBase):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None, disable_radar=False):
|
def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None):
|
||||||
ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
|
ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
|
||||||
ret.carName = "chrysler"
|
ret.carName = "chrysler"
|
||||||
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.chrysler)]
|
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.chrysler)]
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
from typing import Dict, List, Union
|
|
||||||
|
|
||||||
from selfdrive.car import dbc_dict
|
from selfdrive.car import dbc_dict
|
||||||
from selfdrive.car.docs_definitions import CarInfo
|
|
||||||
from cereal import car
|
from cereal import car
|
||||||
Ecu = car.CarParams.Ecu
|
Ecu = car.CarParams.Ecu
|
||||||
|
|
||||||
|
@ -21,16 +18,6 @@ class CAR:
|
||||||
JEEP_CHEROKEE = "JEEP GRAND CHEROKEE V6 2018" # includes 2017 Trailhawk
|
JEEP_CHEROKEE = "JEEP GRAND CHEROKEE V6 2018" # includes 2017 Trailhawk
|
||||||
JEEP_CHEROKEE_2019 = "JEEP GRAND CHEROKEE 2019" # includes 2020 Trailhawk
|
JEEP_CHEROKEE_2019 = "JEEP GRAND CHEROKEE 2019" # includes 2020 Trailhawk
|
||||||
|
|
||||||
|
|
||||||
CAR_INFO: Dict[str, Union[CarInfo, List[CarInfo]]] = {
|
|
||||||
CAR.PACIFICA_2017_HYBRID: CarInfo("Chrysler Pacifica Hybrid 2017-18", "Adaptive Cruise"),
|
|
||||||
CAR.PACIFICA_2019_HYBRID: CarInfo("Chrysler Pacifica Hybrid 2019-21", "Adaptive Cruise"),
|
|
||||||
CAR.PACIFICA_2018: CarInfo("Chrysler Pacifica 2017-18", "Adaptive Cruise"),
|
|
||||||
CAR.PACIFICA_2020: CarInfo("Chrysler Pacifica 2020", "Adaptive Cruise"),
|
|
||||||
CAR.JEEP_CHEROKEE: CarInfo("Jeep Grand Cherokee 2016-18", "Adaptive Cruise", "https://www.youtube.com/watch?v=eLR9o2JkuRk"),
|
|
||||||
CAR.JEEP_CHEROKEE_2019: CarInfo("Jeep Grand Cherokee 2019-20", "Adaptive Cruise", "https://www.youtube.com/watch?v=jBe4lWnRSu4"),
|
|
||||||
}
|
|
||||||
|
|
||||||
# Unique CAN messages:
|
# Unique CAN messages:
|
||||||
# Only the hybrids have 270: 8
|
# Only the hybrids have 270: 8
|
||||||
# Only the gas have 55: 8, 416: 7
|
# Only the gas have 55: 8, 416: 7
|
||||||
|
|
|
@ -1,73 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
import argparse
|
|
||||||
import jinja2
|
|
||||||
import os
|
|
||||||
from enum import Enum
|
|
||||||
from typing import Dict, List
|
|
||||||
|
|
||||||
from common.basedir import BASEDIR
|
|
||||||
from selfdrive.car.docs_definitions import CarInfo, Column, Star, Tier
|
|
||||||
from selfdrive.car.car_helpers import interfaces, get_interface_attr
|
|
||||||
from selfdrive.car.hyundai.radar_interface import RADAR_START_ADDR as HKG_RADAR_START_ADDR
|
|
||||||
from selfdrive.car.tests.routes import non_tested_cars
|
|
||||||
|
|
||||||
|
|
||||||
def get_all_footnotes() -> Dict[Enum, int]:
|
|
||||||
all_footnotes = []
|
|
||||||
for _, footnotes in get_interface_attr("Footnote").items():
|
|
||||||
if footnotes is not None:
|
|
||||||
all_footnotes += footnotes
|
|
||||||
return {fn: idx + 1 for idx, fn in enumerate(all_footnotes)}
|
|
||||||
|
|
||||||
|
|
||||||
ALL_FOOTNOTES: Dict[Enum, int] = get_all_footnotes()
|
|
||||||
CARS_MD_OUT = os.path.join(BASEDIR, "docs", "CARS.md")
|
|
||||||
CARS_MD_TEMPLATE = os.path.join(BASEDIR, "selfdrive", "car", "CARS_template.md")
|
|
||||||
|
|
||||||
|
|
||||||
def get_tier_car_info() -> Dict[Tier, List[CarInfo]]:
|
|
||||||
tier_car_info: Dict[Tier, List[CarInfo]] = {tier: [] for tier in Tier}
|
|
||||||
|
|
||||||
for models in get_interface_attr("CAR_INFO").values():
|
|
||||||
for model, car_info in models.items():
|
|
||||||
# Hyundai exception: those with radar have openpilot longitudinal
|
|
||||||
fingerprint = {0: {}, 1: {HKG_RADAR_START_ADDR: 8}, 2: {}, 3: {}}
|
|
||||||
CP = interfaces[model][0].get_params(model, fingerprint=fingerprint, disable_radar=True)
|
|
||||||
|
|
||||||
if CP.dashcamOnly:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# A platform can include multiple car models
|
|
||||||
if not isinstance(car_info, list):
|
|
||||||
car_info = (car_info,)
|
|
||||||
|
|
||||||
for _car_info in car_info:
|
|
||||||
_car_info.init(CP, non_tested_cars, ALL_FOOTNOTES)
|
|
||||||
tier_car_info[_car_info.tier].append(_car_info)
|
|
||||||
|
|
||||||
# Sort cars by make and model + year
|
|
||||||
for tier, cars in tier_car_info.items():
|
|
||||||
tier_car_info[tier] = sorted(cars, key=lambda x: x.make + x.model)
|
|
||||||
|
|
||||||
return tier_car_info
|
|
||||||
|
|
||||||
|
|
||||||
def generate_cars_md(tier_car_info: Dict[Tier, List[CarInfo]], template_fn: str) -> str:
|
|
||||||
with open(template_fn, "r") as f:
|
|
||||||
template = jinja2.Template(f.read(), trim_blocks=True, lstrip_blocks=True)
|
|
||||||
|
|
||||||
footnotes = [fn.value.text for fn in ALL_FOOTNOTES]
|
|
||||||
return template.render(tiers=tier_car_info, footnotes=footnotes, Star=Star, Column=Column)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
parser = argparse.ArgumentParser(description="Auto generates supported cars documentation",
|
|
||||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
|
||||||
|
|
||||||
parser.add_argument("--template", default=CARS_MD_TEMPLATE, help="Override default template filename")
|
|
||||||
parser.add_argument("--out", default=CARS_MD_OUT, help="Override default generated filename")
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
with open(args.out, 'w') as f:
|
|
||||||
f.write(generate_cars_md(get_tier_car_info(), args.template))
|
|
||||||
print(f"Generated and written to {args.out}")
|
|
|
@ -1,100 +0,0 @@
|
||||||
from cereal import car
|
|
||||||
from collections import namedtuple
|
|
||||||
from dataclasses import dataclass
|
|
||||||
from enum import Enum
|
|
||||||
from typing import Dict, List, Optional, Union, no_type_check
|
|
||||||
|
|
||||||
|
|
||||||
class Tier(Enum):
|
|
||||||
GOLD = "The best openpilot experience. Great highway driving and beyond."
|
|
||||||
SILVER = "A solid highway driving experience, but is limited by stock longitudinal. May be upgraded in the future."
|
|
||||||
BRONZE = "A good highway experience, but may have limited performance in traffic and on sharp turns."
|
|
||||||
|
|
||||||
|
|
||||||
class Column(Enum):
|
|
||||||
MAKE = "Make"
|
|
||||||
MODEL = "Model"
|
|
||||||
PACKAGE = "Supported Package"
|
|
||||||
LONGITUDINAL = "openpilot ACC"
|
|
||||||
FSR_LONGITUDINAL = "Stop and Go"
|
|
||||||
FSR_STEERING = "Steer to 0"
|
|
||||||
STEERING_TORQUE = "Steering Torque"
|
|
||||||
MAINTAINED = "Actively Maintained"
|
|
||||||
|
|
||||||
|
|
||||||
class Star(Enum):
|
|
||||||
FULL = "full"
|
|
||||||
HALF = "half"
|
|
||||||
EMPTY = "empty"
|
|
||||||
|
|
||||||
|
|
||||||
StarColumns = list(Column)[3:]
|
|
||||||
CarFootnote = namedtuple("CarFootnote", ["text", "column", "star"], defaults=[None])
|
|
||||||
|
|
||||||
|
|
||||||
def get_footnote(footnotes: Optional[List[Enum]], column: Column) -> Optional[Enum]:
|
|
||||||
# Returns applicable footnote given current column
|
|
||||||
if footnotes is not None:
|
|
||||||
for fn in footnotes:
|
|
||||||
if fn.value.column == column:
|
|
||||||
return fn
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class CarInfo:
|
|
||||||
name: str
|
|
||||||
package: str
|
|
||||||
video_link: Optional[str] = None
|
|
||||||
footnotes: Optional[List[Enum]] = None
|
|
||||||
min_steer_speed: Optional[float] = None
|
|
||||||
min_enable_speed: Optional[float] = None
|
|
||||||
good_torque: bool = False
|
|
||||||
|
|
||||||
def init(self, CP: car.CarParams, non_tested_cars: List[str], all_footnotes: Dict[Enum, int]):
|
|
||||||
# TODO: set all the min steer speeds in carParams and remove this
|
|
||||||
min_steer_speed = CP.minSteerSpeed
|
|
||||||
if self.min_steer_speed is not None:
|
|
||||||
min_steer_speed = self.min_steer_speed
|
|
||||||
assert CP.minSteerSpeed == 0, f"Minimum steer speed set in both CarInfo and CarParams for {CP.carFingerprint}"
|
|
||||||
|
|
||||||
# TODO: set all the min enable speeds in carParams correctly and remove this
|
|
||||||
min_enable_speed = CP.minEnableSpeed
|
|
||||||
if self.min_enable_speed is not None:
|
|
||||||
min_enable_speed = self.min_enable_speed
|
|
||||||
|
|
||||||
self.make, self.model = self.name.split(' ', 1)
|
|
||||||
self.row = {
|
|
||||||
Column.MAKE: self.make,
|
|
||||||
Column.MODEL: self.model,
|
|
||||||
Column.PACKAGE: self.package,
|
|
||||||
# StarColumns
|
|
||||||
Column.LONGITUDINAL: CP.openpilotLongitudinalControl and not CP.radarOffCan,
|
|
||||||
Column.FSR_LONGITUDINAL: min_enable_speed <= 0.,
|
|
||||||
Column.FSR_STEERING: min_steer_speed <= 0.,
|
|
||||||
Column.STEERING_TORQUE: self.good_torque,
|
|
||||||
Column.MAINTAINED: CP.carFingerprint not in non_tested_cars,
|
|
||||||
}
|
|
||||||
|
|
||||||
self.all_footnotes = all_footnotes
|
|
||||||
for column in StarColumns:
|
|
||||||
self.row[column] = Star.FULL if self.row[column] else Star.EMPTY
|
|
||||||
|
|
||||||
# Demote if footnote specifies a star
|
|
||||||
footnote = get_footnote(self.footnotes, column)
|
|
||||||
if footnote is not None and footnote.value.star is not None:
|
|
||||||
self.row[column] = footnote.value.star
|
|
||||||
|
|
||||||
self.tier = {5: Tier.GOLD, 4: Tier.SILVER}.get(list(self.row.values()).count(Star.FULL), Tier.BRONZE)
|
|
||||||
|
|
||||||
@no_type_check
|
|
||||||
def get_column(self, column: Column, star_icon: str, footnote_tag: str) -> str:
|
|
||||||
item: Union[str, Star] = self.row[column]
|
|
||||||
if column in StarColumns:
|
|
||||||
item = star_icon.format(item.value)
|
|
||||||
|
|
||||||
footnote = get_footnote(self.footnotes, column)
|
|
||||||
if footnote is not None:
|
|
||||||
item += footnote_tag.format(self.all_footnotes[footnote])
|
|
||||||
|
|
||||||
return item
|
|
|
@ -8,7 +8,7 @@ from selfdrive.car.interfaces import CarInterfaceBase
|
||||||
|
|
||||||
class CarInterface(CarInterfaceBase):
|
class CarInterface(CarInterfaceBase):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None, disable_radar=False):
|
def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None):
|
||||||
ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
|
ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
|
||||||
ret.carName = "ford"
|
ret.carName = "ford"
|
||||||
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.ford)]
|
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.ford)]
|
||||||
|
|
|
@ -1,21 +1,12 @@
|
||||||
from typing import Dict, List, Union
|
|
||||||
|
|
||||||
from cereal import car
|
|
||||||
from selfdrive.car import dbc_dict
|
from selfdrive.car import dbc_dict
|
||||||
from selfdrive.car.docs_definitions import CarInfo
|
from cereal import car
|
||||||
Ecu = car.CarParams.Ecu
|
Ecu = car.CarParams.Ecu
|
||||||
|
|
||||||
MAX_ANGLE = 87. # make sure we never command the extremes (0xfff) which cause latching fault
|
MAX_ANGLE = 87. # make sure we never command the extremes (0xfff) which cause latching fault
|
||||||
|
|
||||||
|
|
||||||
class CAR:
|
class CAR:
|
||||||
FUSION = "FORD FUSION 2018"
|
FUSION = "FORD FUSION 2018"
|
||||||
|
|
||||||
|
|
||||||
CAR_INFO: Dict[str, Union[CarInfo, List[CarInfo]]] = {
|
|
||||||
CAR.FUSION: CarInfo("Ford Fusion 2018", "All")
|
|
||||||
}
|
|
||||||
|
|
||||||
DBC = {
|
DBC = {
|
||||||
CAR.FUSION: dbc_dict('ford_fusion_2018_pt', 'ford_fusion_2018_adas'),
|
CAR.FUSION: dbc_dict('ford_fusion_2018_pt', 'ford_fusion_2018_adas'),
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ class CarInterface(CarInterfaceBase):
|
||||||
return CarInterfaceBase.get_steer_feedforward_default
|
return CarInterfaceBase.get_steer_feedforward_default
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None, disable_radar=False):
|
def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None):
|
||||||
ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
|
ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
|
||||||
ret.carName = "gm"
|
ret.carName = "gm"
|
||||||
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.gm)]
|
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.gm)]
|
||||||
|
|
|
@ -1,13 +1,8 @@
|
||||||
from enum import Enum
|
|
||||||
from typing import Dict, List, Union
|
|
||||||
|
|
||||||
from cereal import car
|
from cereal import car
|
||||||
from selfdrive.car import dbc_dict
|
from selfdrive.car import dbc_dict
|
||||||
from selfdrive.car.docs_definitions import CarFootnote, CarInfo, Column
|
|
||||||
Ecu = car.CarParams.Ecu
|
Ecu = car.CarParams.Ecu
|
||||||
|
|
||||||
|
class CarControllerParams():
|
||||||
class CarControllerParams:
|
|
||||||
STEER_MAX = 300 # Safety limit, not LKA max. Trucks use 600.
|
STEER_MAX = 300 # Safety limit, not LKA max. Trucks use 600.
|
||||||
STEER_STEP = 2 # control frames per command
|
STEER_STEP = 2 # control frames per command
|
||||||
STEER_DELTA_UP = 7
|
STEER_DELTA_UP = 7
|
||||||
|
@ -43,7 +38,6 @@ class CarControllerParams:
|
||||||
|
|
||||||
STEER_THRESHOLD = 1.0
|
STEER_THRESHOLD = 1.0
|
||||||
|
|
||||||
|
|
||||||
class CAR:
|
class CAR:
|
||||||
HOLDEN_ASTRA = "HOLDEN ASTRA RS-V BK 2017"
|
HOLDEN_ASTRA = "HOLDEN ASTRA RS-V BK 2017"
|
||||||
VOLT = "CHEVROLET VOLT PREMIER 2017"
|
VOLT = "CHEVROLET VOLT PREMIER 2017"
|
||||||
|
@ -53,26 +47,6 @@ class CAR:
|
||||||
BUICK_REGAL = "BUICK REGAL ESSENCE 2018"
|
BUICK_REGAL = "BUICK REGAL ESSENCE 2018"
|
||||||
ESCALADE_ESV = "CADILLAC ESCALADE ESV 2016"
|
ESCALADE_ESV = "CADILLAC ESCALADE ESV 2016"
|
||||||
|
|
||||||
|
|
||||||
class Footnote(Enum):
|
|
||||||
OBD_II = CarFootnote(
|
|
||||||
'Requires an <a href="https://comma.ai/shop/products/comma-car-harness">OBD-II car harness</a> and ' +
|
|
||||||
'<a href="https://github.com/commaai/openpilot/wiki/GM#hardware">community built ASCM harness</a>. ' +
|
|
||||||
'<b><i>NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).</i></b>',
|
|
||||||
Column.MODEL)
|
|
||||||
|
|
||||||
|
|
||||||
CAR_INFO: Dict[str, Union[CarInfo, List[CarInfo]]] = {
|
|
||||||
CAR.HOLDEN_ASTRA: CarInfo("Holden Astra 2017", "Adaptive Cruise"),
|
|
||||||
CAR.VOLT: CarInfo("Chevrolet Volt 2017-18", "Adaptive Cruise", footnotes=[Footnote.OBD_II], min_enable_speed=0),
|
|
||||||
CAR.CADILLAC_ATS: CarInfo("Cadillac ATS Premium Performance 2018", "Adaptive Cruise"),
|
|
||||||
CAR.MALIBU: CarInfo("Chevrolet Malibu Premier 2017", "Adaptive Cruise"),
|
|
||||||
CAR.ACADIA: CarInfo("GMC Acadia 2018", "Adaptive Cruise", video_link="https://www.youtube.com/watch?v=0ZN6DdsBUZo", footnotes=[Footnote.OBD_II]),
|
|
||||||
CAR.BUICK_REGAL: CarInfo("Buick Regal Essence 2018", "Adaptive Cruise"),
|
|
||||||
CAR.ESCALADE_ESV: CarInfo("Cadillac Escalade ESV 2016", "ACC + LKAS", footnotes=[Footnote.OBD_II]),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class CruiseButtons:
|
class CruiseButtons:
|
||||||
INIT = 0
|
INIT = 0
|
||||||
UNPRESS = 1
|
UNPRESS = 1
|
||||||
|
|
|
@ -1,21 +1,18 @@
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
from cereal import car
|
from cereal import car
|
||||||
from common.conversions import Conversions as CV
|
|
||||||
from common.numpy_fast import clip, interp
|
|
||||||
from common.realtime import DT_CTRL
|
from common.realtime import DT_CTRL
|
||||||
from opendbc.can.packer import CANPacker
|
from selfdrive.controls.lib.drive_helpers import rate_limit
|
||||||
|
from common.numpy_fast import clip, interp
|
||||||
from selfdrive.car import create_gas_interceptor_command
|
from selfdrive.car import create_gas_interceptor_command
|
||||||
from selfdrive.car.honda import hondacan
|
from selfdrive.car.honda import hondacan
|
||||||
from selfdrive.car.honda.values import CruiseButtons, VISUAL_HUD, HONDA_BOSCH, HONDA_NIDEC_ALT_PCM_ACCEL, CarControllerParams
|
from selfdrive.car.honda.values import CruiseButtons, VISUAL_HUD, HONDA_BOSCH, HONDA_NIDEC_ALT_PCM_ACCEL, CarControllerParams
|
||||||
from selfdrive.controls.lib.drive_helpers import rate_limit
|
from opendbc.can.packer import CANPacker
|
||||||
|
|
||||||
VisualAlert = car.CarControl.HUDControl.VisualAlert
|
VisualAlert = car.CarControl.HUDControl.VisualAlert
|
||||||
LongCtrlState = car.CarControl.Actuators.LongControlState
|
LongCtrlState = car.CarControl.Actuators.LongControlState
|
||||||
|
|
||||||
|
|
||||||
def compute_gb_honda_bosch(accel, speed):
|
def compute_gb_honda_bosch(accel, speed):
|
||||||
# TODO returns 0s, is unused
|
#TODO returns 0s, is unused
|
||||||
return 0.0, 0.0
|
return 0.0, 0.0
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,14 +33,14 @@ def compute_gas_brake(accel, speed, fingerprint):
|
||||||
return compute_gb_honda_nidec(accel, speed)
|
return compute_gb_honda_nidec(accel, speed)
|
||||||
|
|
||||||
|
|
||||||
# TODO not clear this does anything useful
|
#TODO not clear this does anything useful
|
||||||
def actuator_hysteresis(brake, braking, brake_steady, v_ego, car_fingerprint):
|
def actuator_hystereses(brake, braking, brake_steady, v_ego, car_fingerprint):
|
||||||
# hyst params
|
# hyst params
|
||||||
brake_hyst_on = 0.02 # to activate brakes exceed this value
|
brake_hyst_on = 0.02 # to activate brakes exceed this value
|
||||||
brake_hyst_off = 0.005 # to deactivate brakes below this value
|
brake_hyst_off = 0.005 # to deactivate brakes below this value
|
||||||
brake_hyst_gap = 0.01 # don't change brake command for small oscillations within this value
|
brake_hyst_gap = 0.01 # don't change brake command for small oscillations within this value
|
||||||
|
|
||||||
# *** hysteresis logic to avoid brake blinking. go above 0.1 to trigger
|
#*** hysteresis logic to avoid brake blinking. go above 0.1 to trigger
|
||||||
if (brake < brake_hyst_on and not braking) or brake < brake_hyst_off:
|
if (brake < brake_hyst_on and not braking) or brake < brake_hyst_off:
|
||||||
brake = 0.
|
brake = 0.
|
||||||
braking = brake > 0.
|
braking = brake > 0.
|
||||||
|
@ -96,170 +93,164 @@ def process_hud_alert(hud_alert):
|
||||||
|
|
||||||
HUDData = namedtuple("HUDData",
|
HUDData = namedtuple("HUDData",
|
||||||
["pcm_accel", "v_cruise", "car",
|
["pcm_accel", "v_cruise", "car",
|
||||||
"lanes", "fcw", "acc_alert", "steer_required"])
|
"lanes", "fcw", "acc_alert", "steer_required"])
|
||||||
|
|
||||||
|
|
||||||
class CarController:
|
class CarController():
|
||||||
def __init__(self, dbc_name, CP, VM):
|
def __init__(self, dbc_name, CP, VM):
|
||||||
self.CP = CP
|
|
||||||
self.packer = CANPacker(dbc_name)
|
|
||||||
self.params = CarControllerParams(CP)
|
|
||||||
self.frame = 0
|
|
||||||
|
|
||||||
self.braking = False
|
self.braking = False
|
||||||
self.brake_steady = 0.
|
self.brake_steady = 0.
|
||||||
self.brake_last = 0.
|
self.brake_last = 0.
|
||||||
self.apply_brake_last = 0
|
self.apply_brake_last = 0
|
||||||
self.last_pump_ts = 0.
|
self.last_pump_ts = 0.
|
||||||
|
self.packer = CANPacker(dbc_name)
|
||||||
|
|
||||||
self.accel = 0
|
self.accel = 0
|
||||||
self.speed = 0
|
self.speed = 0
|
||||||
self.gas = 0
|
self.gas = 0
|
||||||
self.brake = 0
|
self.brake = 0
|
||||||
|
|
||||||
def update(self, CC, CS):
|
self.params = CarControllerParams(CP)
|
||||||
actuators = CC.actuators
|
|
||||||
hud_control = CC.hudControl
|
|
||||||
hud_v_cruise = hud_control.setSpeed * CV.MS_TO_KPH if hud_control.speedVisible else 255
|
|
||||||
pcm_cancel_cmd = CC.cruiseControl.cancel
|
|
||||||
|
|
||||||
if CC.longActive:
|
def update(self, c, CS, frame, actuators, pcm_cancel_cmd,
|
||||||
|
hud_v_cruise, hud_show_lanes, hud_show_car, hud_alert):
|
||||||
|
|
||||||
|
P = self.params
|
||||||
|
|
||||||
|
if c.longActive:
|
||||||
accel = actuators.accel
|
accel = actuators.accel
|
||||||
gas, brake = compute_gas_brake(actuators.accel, CS.out.vEgo, self.CP.carFingerprint)
|
gas, brake = compute_gas_brake(actuators.accel, CS.out.vEgo, CS.CP.carFingerprint)
|
||||||
else:
|
else:
|
||||||
accel = 0.0
|
accel = 0.0
|
||||||
gas, brake = 0.0, 0.0
|
gas, brake = 0.0, 0.0
|
||||||
|
|
||||||
# *** apply brake hysteresis ***
|
# *** apply brake hysteresis ***
|
||||||
pre_limit_brake, self.braking, self.brake_steady = actuator_hysteresis(brake, self.braking, self.brake_steady,
|
pre_limit_brake, self.braking, self.brake_steady = actuator_hystereses(brake, self.braking, self.brake_steady, CS.out.vEgo, CS.CP.carFingerprint)
|
||||||
CS.out.vEgo, self.CP.carFingerprint)
|
|
||||||
|
|
||||||
# *** rate limit after the enable check ***
|
# *** rate limit after the enable check ***
|
||||||
self.brake_last = rate_limit(pre_limit_brake, self.brake_last, -2., DT_CTRL)
|
self.brake_last = rate_limit(pre_limit_brake, self.brake_last, -2., DT_CTRL)
|
||||||
|
|
||||||
# vehicle hud display, wait for one update from 10Hz 0x304 msg
|
# vehicle hud display, wait for one update from 10Hz 0x304 msg
|
||||||
if hud_control.lanesVisible:
|
if hud_show_lanes:
|
||||||
hud_lanes = 1
|
hud_lanes = 1
|
||||||
else:
|
else:
|
||||||
hud_lanes = 0
|
hud_lanes = 0
|
||||||
|
|
||||||
if CC.enabled:
|
if c.enabled:
|
||||||
if hud_control.leadVisible:
|
if hud_show_car:
|
||||||
hud_car = 2
|
hud_car = 2
|
||||||
else:
|
else:
|
||||||
hud_car = 1
|
hud_car = 1
|
||||||
else:
|
else:
|
||||||
hud_car = 0
|
hud_car = 0
|
||||||
|
|
||||||
fcw_display, steer_required, acc_alert = process_hud_alert(hud_control.visualAlert)
|
fcw_display, steer_required, acc_alert = process_hud_alert(hud_alert)
|
||||||
|
|
||||||
|
|
||||||
# **** process the car messages ****
|
# **** process the car messages ****
|
||||||
|
|
||||||
# steer torque is converted back to CAN reference (positive when steering right)
|
# steer torque is converted back to CAN reference (positive when steering right)
|
||||||
apply_steer = int(interp(-actuators.steer * self.params.STEER_MAX,
|
apply_steer = int(interp(-actuators.steer * P.STEER_MAX, P.STEER_LOOKUP_BP, P.STEER_LOOKUP_V))
|
||||||
self.params.STEER_LOOKUP_BP, self.params.STEER_LOOKUP_V))
|
|
||||||
|
|
||||||
# Send CAN commands
|
# Send CAN commands.
|
||||||
can_sends = []
|
can_sends = []
|
||||||
|
|
||||||
# tester present - w/ no response (keeps radar disabled)
|
# tester present - w/ no response (keeps radar disabled)
|
||||||
if self.CP.carFingerprint in HONDA_BOSCH and self.CP.openpilotLongitudinalControl:
|
if CS.CP.carFingerprint in HONDA_BOSCH and CS.CP.openpilotLongitudinalControl:
|
||||||
if self.frame % 10 == 0:
|
if (frame % 10) == 0:
|
||||||
can_sends.append((0x18DAB0F1, 0, b"\x02\x3E\x80\x00\x00\x00\x00\x00", 1))
|
can_sends.append((0x18DAB0F1, 0, b"\x02\x3E\x80\x00\x00\x00\x00\x00", 1))
|
||||||
|
|
||||||
# Send steering command.
|
# Send steering command.
|
||||||
idx = self.frame % 4
|
idx = frame % 4
|
||||||
can_sends.append(hondacan.create_steering_control(self.packer, apply_steer, CC.latActive, self.CP.carFingerprint,
|
can_sends.append(hondacan.create_steering_control(self.packer, apply_steer,
|
||||||
idx, CS.CP.openpilotLongitudinalControl))
|
c.latActive, CS.CP.carFingerprint, idx, CS.CP.openpilotLongitudinalControl))
|
||||||
|
|
||||||
stopping = actuators.longControlState == LongCtrlState.stopping
|
stopping = actuators.longControlState == LongCtrlState.stopping
|
||||||
|
|
||||||
# wind brake from air resistance decel at high speed
|
# wind brake from air resistance decel at high speed
|
||||||
wind_brake = interp(CS.out.vEgo, [0.0, 2.3, 35.0], [0.001, 0.002, 0.15])
|
wind_brake = interp(CS.out.vEgo, [0.0, 2.3, 35.0], [0.001, 0.002, 0.15])
|
||||||
# all of this is only relevant for HONDA NIDEC
|
# all of this is only relevant for HONDA NIDEC
|
||||||
max_accel = interp(CS.out.vEgo, self.params.NIDEC_MAX_ACCEL_BP, self.params.NIDEC_MAX_ACCEL_V)
|
max_accel = interp(CS.out.vEgo, P.NIDEC_MAX_ACCEL_BP, P.NIDEC_MAX_ACCEL_V)
|
||||||
# TODO this 1.44 is just to maintain previous behavior
|
# TODO this 1.44 is just to maintain previous behavior
|
||||||
pcm_speed_BP = [-wind_brake,
|
pcm_speed_BP = [-wind_brake,
|
||||||
-wind_brake * (3 / 4),
|
-wind_brake*(3/4),
|
||||||
0.0,
|
0.0,
|
||||||
0.5]
|
0.5]
|
||||||
# The Honda ODYSSEY seems to have different PCM_ACCEL
|
# The Honda ODYSSEY seems to have different PCM_ACCEL
|
||||||
# msgs, is it other cars too?
|
# msgs, is it other cars too?
|
||||||
if self.CP.enableGasInterceptor or not CC.longActive:
|
if CS.CP.enableGasInterceptor:
|
||||||
pcm_speed = 0.0
|
pcm_speed = 0.0
|
||||||
pcm_accel = int(0.0)
|
pcm_accel = int(0.0)
|
||||||
elif self.CP.carFingerprint in HONDA_NIDEC_ALT_PCM_ACCEL:
|
elif CS.CP.carFingerprint in HONDA_NIDEC_ALT_PCM_ACCEL:
|
||||||
pcm_speed_V = [0.0,
|
pcm_speed_V = [0.0,
|
||||||
clip(CS.out.vEgo - 3.0, 0.0, 100.0),
|
clip(CS.out.vEgo - 3.0, 0.0, 100.0),
|
||||||
clip(CS.out.vEgo + 0.0, 0.0, 100.0),
|
clip(CS.out.vEgo + 0.0, 0.0, 100.0),
|
||||||
clip(CS.out.vEgo + 5.0, 0.0, 100.0)]
|
clip(CS.out.vEgo + 5.0, 0.0, 100.0)]
|
||||||
pcm_speed = interp(gas - brake, pcm_speed_BP, pcm_speed_V)
|
pcm_speed = interp(gas-brake, pcm_speed_BP, pcm_speed_V)
|
||||||
pcm_accel = int(1.0 * 0xc6)
|
pcm_accel = int((1.0) * 0xc6)
|
||||||
else:
|
else:
|
||||||
pcm_speed_V = [0.0,
|
pcm_speed_V = [0.0,
|
||||||
clip(CS.out.vEgo - 2.0, 0.0, 100.0),
|
clip(CS.out.vEgo - 2.0, 0.0, 100.0),
|
||||||
clip(CS.out.vEgo + 2.0, 0.0, 100.0),
|
clip(CS.out.vEgo + 2.0, 0.0, 100.0),
|
||||||
clip(CS.out.vEgo + 5.0, 0.0, 100.0)]
|
clip(CS.out.vEgo + 5.0, 0.0, 100.0)]
|
||||||
pcm_speed = interp(gas - brake, pcm_speed_BP, pcm_speed_V)
|
pcm_speed = interp(gas-brake, pcm_speed_BP, pcm_speed_V)
|
||||||
pcm_accel = int(clip((accel / 1.44) / max_accel, 0.0, 1.0) * 0xc6)
|
pcm_accel = int(clip((accel/1.44)/max_accel, 0.0, 1.0) * 0xc6)
|
||||||
|
|
||||||
if not self.CP.openpilotLongitudinalControl:
|
if not CS.CP.openpilotLongitudinalControl:
|
||||||
if self.frame % 2 == 0:
|
if (frame % 2) == 0:
|
||||||
idx = self.frame // 2
|
idx = frame // 2
|
||||||
can_sends.append(hondacan.create_bosch_supplemental_1(self.packer, self.CP.carFingerprint, idx))
|
can_sends.append(hondacan.create_bosch_supplemental_1(self.packer, CS.CP.carFingerprint, idx))
|
||||||
# If using stock ACC, spam cancel command to kill gas when OP disengages.
|
# If using stock ACC, spam cancel command to kill gas when OP disengages.
|
||||||
if pcm_cancel_cmd:
|
if pcm_cancel_cmd:
|
||||||
can_sends.append(hondacan.spam_buttons_command(self.packer, CruiseButtons.CANCEL, idx, self.CP.carFingerprint))
|
can_sends.append(hondacan.spam_buttons_command(self.packer, CruiseButtons.CANCEL, idx, CS.CP.carFingerprint))
|
||||||
elif CS.out.cruiseState.standstill:
|
elif CS.out.cruiseState.standstill:
|
||||||
can_sends.append(hondacan.spam_buttons_command(self.packer, CruiseButtons.RES_ACCEL, idx, self.CP.carFingerprint))
|
can_sends.append(hondacan.spam_buttons_command(self.packer, CruiseButtons.RES_ACCEL, idx, CS.CP.carFingerprint))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Send gas and brake commands.
|
# Send gas and brake commands.
|
||||||
if self.frame % 2 == 0:
|
if (frame % 2) == 0:
|
||||||
idx = self.frame // 2
|
idx = frame // 2
|
||||||
ts = self.frame * DT_CTRL
|
ts = frame * DT_CTRL
|
||||||
|
|
||||||
if self.CP.carFingerprint in HONDA_BOSCH:
|
if CS.CP.carFingerprint in HONDA_BOSCH:
|
||||||
self.accel = clip(accel, self.params.BOSCH_ACCEL_MIN, self.params.BOSCH_ACCEL_MAX)
|
self.accel = clip(accel, P.BOSCH_ACCEL_MIN, P.BOSCH_ACCEL_MAX)
|
||||||
self.gas = interp(accel, self.params.BOSCH_GAS_LOOKUP_BP, self.params.BOSCH_GAS_LOOKUP_V)
|
self.gas = interp(accel, P.BOSCH_GAS_LOOKUP_BP, P.BOSCH_GAS_LOOKUP_V)
|
||||||
can_sends.extend(hondacan.create_acc_commands(self.packer, CC.enabled, CC.longActive, accel, self.gas,
|
can_sends.extend(hondacan.create_acc_commands(self.packer, c.enabled, c.longActive, accel, self.gas, idx, stopping, CS.CP.carFingerprint))
|
||||||
idx, stopping, self.CP.carFingerprint))
|
|
||||||
else:
|
else:
|
||||||
apply_brake = clip(self.brake_last - wind_brake, 0.0, 1.0)
|
apply_brake = clip(self.brake_last - wind_brake, 0.0, 1.0)
|
||||||
apply_brake = int(clip(apply_brake * self.params.NIDEC_BRAKE_MAX, 0, self.params.NIDEC_BRAKE_MAX - 1))
|
apply_brake = int(clip(apply_brake * P.NIDEC_BRAKE_MAX, 0, P.NIDEC_BRAKE_MAX - 1))
|
||||||
pump_on, self.last_pump_ts = brake_pump_hysteresis(apply_brake, self.apply_brake_last, self.last_pump_ts, ts)
|
pump_on, self.last_pump_ts = brake_pump_hysteresis(apply_brake, self.apply_brake_last, self.last_pump_ts, ts)
|
||||||
|
|
||||||
pcm_override = True
|
pcm_override = True
|
||||||
can_sends.append(hondacan.create_brake_command(self.packer, apply_brake, pump_on,
|
can_sends.append(hondacan.create_brake_command(self.packer, apply_brake, pump_on,
|
||||||
pcm_override, pcm_cancel_cmd, fcw_display, idx,
|
pcm_override, pcm_cancel_cmd, fcw_display, idx, CS.CP.carFingerprint, CS.stock_brake))
|
||||||
self.CP.carFingerprint, CS.stock_brake))
|
|
||||||
self.apply_brake_last = apply_brake
|
self.apply_brake_last = apply_brake
|
||||||
self.brake = apply_brake / self.params.NIDEC_BRAKE_MAX
|
self.brake = apply_brake / P.NIDEC_BRAKE_MAX
|
||||||
|
|
||||||
if self.CP.enableGasInterceptor:
|
if CS.CP.enableGasInterceptor:
|
||||||
# way too aggressive at low speed without this
|
# way too aggressive at low speed without this
|
||||||
gas_mult = interp(CS.out.vEgo, [0., 10.], [0.4, 1.0])
|
gas_mult = interp(CS.out.vEgo, [0., 10.], [0.4, 1.0])
|
||||||
# send exactly zero if apply_gas is zero. Interceptor will send the max between read value and apply_gas.
|
# send exactly zero if apply_gas is zero. Interceptor will send the max between read value and apply_gas.
|
||||||
# This prevents unexpected pedal range rescaling
|
# This prevents unexpected pedal range rescaling
|
||||||
# Sending non-zero gas when OP is not enabled will cause the PCM not to respond to throttle as expected
|
# Sending non-zero gas when OP is not enabled will cause the PCM not to respond to throttle as expected
|
||||||
# when you do enable.
|
# when you do enable.
|
||||||
if CC.longActive:
|
if c.longActive:
|
||||||
self.gas = clip(gas_mult * (gas - brake + wind_brake * 3 / 4), 0., 1.)
|
self.gas = clip(gas_mult * (gas - brake + wind_brake*3/4), 0., 1.)
|
||||||
else:
|
else:
|
||||||
self.gas = 0.0
|
self.gas = 0.0
|
||||||
can_sends.append(create_gas_interceptor_command(self.packer, self.gas, idx))
|
can_sends.append(create_gas_interceptor_command(self.packer, self.gas, idx))
|
||||||
|
|
||||||
# Send dashboard UI commands.
|
# Send dashboard UI commands.
|
||||||
if self.frame % 10 == 0:
|
if (frame % 10) == 0:
|
||||||
idx = (self.frame // 10) % 4
|
idx = (frame//10) % 4
|
||||||
hud = HUDData(int(pcm_accel), int(round(hud_v_cruise)), hud_car,
|
hud = HUDData(int(pcm_accel), int(round(hud_v_cruise)), hud_car,
|
||||||
hud_lanes, fcw_display, acc_alert, steer_required)
|
hud_lanes, fcw_display, acc_alert, steer_required)
|
||||||
can_sends.extend(hondacan.create_ui_commands(self.packer, self.CP, pcm_speed, hud, CS.is_metric, idx, CS.stock_hud))
|
can_sends.extend(hondacan.create_ui_commands(self.packer, CS.CP, pcm_speed, hud, CS.is_metric, idx, CS.stock_hud))
|
||||||
|
|
||||||
if self.CP.openpilotLongitudinalControl and self.CP.carFingerprint not in HONDA_BOSCH:
|
if (CS.CP.openpilotLongitudinalControl) and (CS.CP.carFingerprint not in HONDA_BOSCH):
|
||||||
self.speed = pcm_speed
|
self.speed = pcm_speed
|
||||||
|
|
||||||
if not self.CP.enableGasInterceptor:
|
if not CS.CP.enableGasInterceptor:
|
||||||
self.gas = pcm_accel / 0xc6
|
self.gas = pcm_accel / 0xc6
|
||||||
|
|
||||||
new_actuators = actuators.copy()
|
new_actuators = actuators.copy()
|
||||||
|
@ -268,5 +259,4 @@ class CarController:
|
||||||
new_actuators.gas = self.gas
|
new_actuators.gas = self.gas
|
||||||
new_actuators.brake = self.brake
|
new_actuators.brake = self.brake
|
||||||
|
|
||||||
self.frame += 1
|
|
||||||
return new_actuators, can_sends
|
return new_actuators, can_sends
|
||||||
|
|
|
@ -3,6 +3,7 @@ from cereal import car
|
||||||
from panda import Panda
|
from panda import Panda
|
||||||
from common.conversions import Conversions as CV
|
from common.conversions import Conversions as CV
|
||||||
from common.numpy_fast import interp
|
from common.numpy_fast import interp
|
||||||
|
from common.params import Params
|
||||||
from selfdrive.car.honda.values import CarControllerParams, CruiseButtons, HondaFlags, CAR, HONDA_BOSCH, HONDA_NIDEC_ALT_SCM_MESSAGES, HONDA_BOSCH_ALT_BRAKE_SIGNAL
|
from selfdrive.car.honda.values import CarControllerParams, CruiseButtons, HondaFlags, CAR, HONDA_BOSCH, HONDA_NIDEC_ALT_SCM_MESSAGES, HONDA_BOSCH_ALT_BRAKE_SIGNAL
|
||||||
from selfdrive.car import STD_CARGO_KG, CivicParams, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config
|
from selfdrive.car import STD_CARGO_KG, CivicParams, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config
|
||||||
from selfdrive.car.interfaces import CarInterfaceBase
|
from selfdrive.car.interfaces import CarInterfaceBase
|
||||||
|
@ -27,7 +28,7 @@ class CarInterface(CarInterfaceBase):
|
||||||
return CarControllerParams.NIDEC_ACCEL_MIN, interp(current_speed, ACCEL_MAX_BP, ACCEL_MAX_VALS)
|
return CarControllerParams.NIDEC_ACCEL_MIN, interp(current_speed, ACCEL_MAX_BP, ACCEL_MAX_VALS)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=[], disable_radar=False): # pylint: disable=dangerous-default-value
|
def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=[]): # pylint: disable=dangerous-default-value
|
||||||
ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
|
ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
|
||||||
ret.carName = "honda"
|
ret.carName = "honda"
|
||||||
|
|
||||||
|
@ -37,7 +38,7 @@ class CarInterface(CarInterfaceBase):
|
||||||
|
|
||||||
# Disable the radar and let openpilot control longitudinal
|
# Disable the radar and let openpilot control longitudinal
|
||||||
# WARNING: THIS DISABLES AEB!
|
# WARNING: THIS DISABLES AEB!
|
||||||
ret.openpilotLongitudinalControl = disable_radar
|
ret.openpilotLongitudinalControl = Params().get_bool("DisableRadar")
|
||||||
|
|
||||||
ret.pcmCruise = not ret.openpilotLongitudinalControl
|
ret.pcmCruise = not ret.openpilotLongitudinalControl
|
||||||
else:
|
else:
|
||||||
|
@ -402,8 +403,8 @@ class CarInterface(CarInterfaceBase):
|
||||||
for b in ret.buttonEvents:
|
for b in ret.buttonEvents:
|
||||||
|
|
||||||
# do enable on both accel and decel buttons
|
# do enable on both accel and decel buttons
|
||||||
if not self.CP.pcmCruise:
|
if b.type in (ButtonType.accelCruise, ButtonType.decelCruise) and not b.pressed:
|
||||||
if b.type in (ButtonType.accelCruise, ButtonType.decelCruise) and not b.pressed:
|
if not self.CP.pcmCruise:
|
||||||
events.add(EventName.buttonEnable)
|
events.add(EventName.buttonEnable)
|
||||||
|
|
||||||
# do disable on button down
|
# do disable on button down
|
||||||
|
@ -418,5 +419,17 @@ class CarInterface(CarInterfaceBase):
|
||||||
# pass in a car.CarControl
|
# pass in a car.CarControl
|
||||||
# to be called @ 100hz
|
# to be called @ 100hz
|
||||||
def apply(self, c):
|
def apply(self, c):
|
||||||
ret = self.CC.update(c, self.CS)
|
hud_control = c.hudControl
|
||||||
|
if hud_control.speedVisible:
|
||||||
|
hud_v_cruise = hud_control.setSpeed * CV.MS_TO_KPH
|
||||||
|
else:
|
||||||
|
hud_v_cruise = 255
|
||||||
|
|
||||||
|
ret = self.CC.update(c, self.CS, self.frame,
|
||||||
|
c.actuators, c.cruiseControl.cancel,
|
||||||
|
hud_v_cruise, hud_control.lanesVisible,
|
||||||
|
hud_show_car=hud_control.leadVisible,
|
||||||
|
hud_alert=hud_control.visualAlert)
|
||||||
|
|
||||||
|
self.frame += 1
|
||||||
return ret
|
return ret
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
from enum import Enum, IntFlag
|
from enum import IntFlag
|
||||||
from typing import Dict, List, Union
|
|
||||||
|
|
||||||
from cereal import car
|
from cereal import car
|
||||||
from selfdrive.car import dbc_dict
|
from selfdrive.car import dbc_dict
|
||||||
from selfdrive.car.docs_definitions import CarFootnote, CarInfo, Column
|
|
||||||
from common.conversions import Conversions as CV
|
|
||||||
|
|
||||||
Ecu = car.CarParams.Ecu
|
Ecu = car.CarParams.Ecu
|
||||||
VisualAlert = car.CarControl.HUDControl.VisualAlert
|
VisualAlert = car.CarControl.HUDControl.VisualAlert
|
||||||
|
|
||||||
class CarControllerParams:
|
|
||||||
|
class CarControllerParams():
|
||||||
# Allow small margin below -3.5 m/s^2 from ISO 15622:2018 since we
|
# Allow small margin below -3.5 m/s^2 from ISO 15622:2018 since we
|
||||||
# perform the closed loop control, and might need some
|
# perform the closed loop control, and might need some
|
||||||
# to apply some more braking if we're on a downhill slope.
|
# to apply some more braking if we're on a downhill slope.
|
||||||
|
@ -65,7 +63,6 @@ VISUAL_HUD = {
|
||||||
VisualAlert.speedTooHigh: 8
|
VisualAlert.speedTooHigh: 8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class CAR:
|
class CAR:
|
||||||
ACCORD = "HONDA ACCORD 2018"
|
ACCORD = "HONDA ACCORD 2018"
|
||||||
ACCORDH = "HONDA ACCORD HYBRID 2018"
|
ACCORDH = "HONDA ACCORD HYBRID 2018"
|
||||||
|
@ -90,43 +87,6 @@ class CAR:
|
||||||
INSIGHT = "HONDA INSIGHT 2019"
|
INSIGHT = "HONDA INSIGHT 2019"
|
||||||
HONDA_E = "HONDA E 2020"
|
HONDA_E = "HONDA E 2020"
|
||||||
|
|
||||||
|
|
||||||
class Footnote(Enum):
|
|
||||||
CIVIC_DIESEL = CarFootnote(
|
|
||||||
"2019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph.",
|
|
||||||
Column.FSR_STEERING)
|
|
||||||
|
|
||||||
|
|
||||||
CAR_INFO: Dict[str, Union[CarInfo, List[CarInfo]]] = {
|
|
||||||
CAR.ACCORD: [
|
|
||||||
CarInfo("Honda Accord 2018-21", "All", video_link="https://www.youtube.com/watch?v=mrUwlj3Mi58", min_steer_speed=3. * CV.MPH_TO_MS),
|
|
||||||
CarInfo("Honda Inspire 2018", "All", min_steer_speed=3. * CV.MPH_TO_MS),
|
|
||||||
],
|
|
||||||
CAR.ACCORDH: CarInfo("Honda Accord Hybrid 2018-21", "All", min_steer_speed=3. * CV.MPH_TO_MS),
|
|
||||||
CAR.CIVIC: CarInfo("Honda Civic 2016-18", "Honda Sensing", min_steer_speed=12. * CV.MPH_TO_MS),
|
|
||||||
CAR.CIVIC_BOSCH: [
|
|
||||||
CarInfo("Honda Civic 2019-20", "All", video_link="https://www.youtube.com/watch?v=4Iz1Mz5LGF8", footnotes=[Footnote.CIVIC_DIESEL], min_steer_speed=2. * CV.MPH_TO_MS),
|
|
||||||
CarInfo("Honda Civic Hatchback 2017-21", "Honda Sensing", min_steer_speed=12. * CV.MPH_TO_MS),
|
|
||||||
],
|
|
||||||
CAR.ACURA_ILX: CarInfo("Acura ILX 2016-19", "AcuraWatch Plus", min_steer_speed=25. * CV.MPH_TO_MS),
|
|
||||||
CAR.CRV: CarInfo("Honda CR-V 2015-16", "Touring", min_steer_speed=12. * CV.MPH_TO_MS),
|
|
||||||
CAR.CRV_5G: CarInfo("Honda CR-V 2017-21", "Honda Sensing", min_steer_speed=12. * CV.MPH_TO_MS),
|
|
||||||
# CAR.CRV_EU: CarInfo("Honda CR-V EU", "Touring"), # Euro version of CRV Touring
|
|
||||||
CAR.CRV_HYBRID: CarInfo("Honda CR-V Hybrid 2017-19", "Honda Sensing", min_steer_speed=12. * CV.MPH_TO_MS),
|
|
||||||
CAR.FIT: CarInfo("Honda Fit 2018-19", "Honda Sensing", min_steer_speed=12. * CV.MPH_TO_MS),
|
|
||||||
CAR.FREED: CarInfo("Honda Freed 2020", "Honda Sensing", min_steer_speed=12. * CV.MPH_TO_MS),
|
|
||||||
CAR.HRV: CarInfo("Honda HR-V 2019-20", "Honda Sensing", min_steer_speed=12. * CV.MPH_TO_MS),
|
|
||||||
CAR.ODYSSEY: CarInfo("Honda Odyssey 2018-20", "Honda Sensing"),
|
|
||||||
CAR.ACURA_RDX: CarInfo("Acura RDX 2016-18", "AcuraWatch Plus", min_steer_speed=12. * CV.MPH_TO_MS),
|
|
||||||
CAR.ACURA_RDX_3G: CarInfo("Acura RDX 2019-21", "All", min_steer_speed=3. * CV.MPH_TO_MS),
|
|
||||||
CAR.PILOT: CarInfo("Honda Pilot 2016-21", "Honda Sensing", min_steer_speed=12. * CV.MPH_TO_MS),
|
|
||||||
CAR.PASSPORT: CarInfo("Honda Passport 2019-21", "All", min_steer_speed=12. * CV.MPH_TO_MS),
|
|
||||||
CAR.RIDGELINE: CarInfo("Honda Ridgeline 2017-21", "Honda Sensing", min_steer_speed=12. * CV.MPH_TO_MS),
|
|
||||||
CAR.INSIGHT: CarInfo("Honda Insight 2019-21", "All", min_steer_speed=3. * CV.MPH_TO_MS),
|
|
||||||
CAR.HONDA_E: CarInfo("Honda e 2020", "All", min_steer_speed=3. * CV.MPH_TO_MS),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
FW_VERSIONS = {
|
FW_VERSIONS = {
|
||||||
CAR.ACCORD: {
|
CAR.ACCORD: {
|
||||||
(Ecu.programmedFuelInjection, 0x18da10f1, None): [
|
(Ecu.programmedFuelInjection, 0x18da10f1, None): [
|
||||||
|
|
|
@ -11,35 +11,34 @@ VisualAlert = car.CarControl.HUDControl.VisualAlert
|
||||||
LongCtrlState = car.CarControl.Actuators.LongControlState
|
LongCtrlState = car.CarControl.Actuators.LongControlState
|
||||||
|
|
||||||
|
|
||||||
def process_hud_alert(enabled, fingerprint, hud_control):
|
def process_hud_alert(enabled, fingerprint, visual_alert, left_lane,
|
||||||
sys_warning = (hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw))
|
right_lane, left_lane_depart, right_lane_depart):
|
||||||
|
sys_warning = (visual_alert in (VisualAlert.steerRequired, VisualAlert.ldw))
|
||||||
|
|
||||||
# initialize to no line visible
|
# initialize to no line visible
|
||||||
sys_state = 1
|
sys_state = 1
|
||||||
if hud_control.leftLaneVisible and hud_control.rightLaneVisible or sys_warning: # HUD alert only display when LKAS status is active
|
if left_lane and right_lane or sys_warning: # HUD alert only display when LKAS status is active
|
||||||
sys_state = 3 if enabled or sys_warning else 4
|
sys_state = 3 if enabled or sys_warning else 4
|
||||||
elif hud_control.leftLaneVisible:
|
elif left_lane:
|
||||||
sys_state = 5
|
sys_state = 5
|
||||||
elif hud_control.rightLaneVisible:
|
elif right_lane:
|
||||||
sys_state = 6
|
sys_state = 6
|
||||||
|
|
||||||
# initialize to no warnings
|
# initialize to no warnings
|
||||||
left_lane_warning = 0
|
left_lane_warning = 0
|
||||||
right_lane_warning = 0
|
right_lane_warning = 0
|
||||||
if hud_control.leftLaneDepart:
|
if left_lane_depart:
|
||||||
left_lane_warning = 1 if fingerprint in (CAR.GENESIS_G90, CAR.GENESIS_G80) else 2
|
left_lane_warning = 1 if fingerprint in (CAR.GENESIS_G90, CAR.GENESIS_G80) else 2
|
||||||
if hud_control.rightLaneDepart:
|
if right_lane_depart:
|
||||||
right_lane_warning = 1 if fingerprint in (CAR.GENESIS_G90, CAR.GENESIS_G80) else 2
|
right_lane_warning = 1 if fingerprint in (CAR.GENESIS_G90, CAR.GENESIS_G80) else 2
|
||||||
|
|
||||||
return sys_warning, sys_state, left_lane_warning, right_lane_warning
|
return sys_warning, sys_state, left_lane_warning, right_lane_warning
|
||||||
|
|
||||||
|
|
||||||
class CarController:
|
class CarController():
|
||||||
def __init__(self, dbc_name, CP, VM):
|
def __init__(self, dbc_name, CP, VM):
|
||||||
self.CP = CP
|
self.p = CarControllerParams(CP)
|
||||||
self.params = CarControllerParams(CP)
|
|
||||||
self.packer = CANPacker(dbc_name)
|
self.packer = CANPacker(dbc_name)
|
||||||
self.frame = 0
|
|
||||||
|
|
||||||
self.apply_steer_last = 0
|
self.apply_steer_last = 0
|
||||||
self.car_fingerprint = CP.carFingerprint
|
self.car_fingerprint = CP.carFingerprint
|
||||||
|
@ -47,49 +46,47 @@ class CarController:
|
||||||
self.last_resume_frame = 0
|
self.last_resume_frame = 0
|
||||||
self.accel = 0
|
self.accel = 0
|
||||||
|
|
||||||
def update(self, CC, CS):
|
def update(self, c, CS, frame, actuators, pcm_cancel_cmd, visual_alert, hud_speed,
|
||||||
actuators = CC.actuators
|
left_lane, right_lane, left_lane_depart, right_lane_depart):
|
||||||
hud_control = CC.hudControl
|
|
||||||
pcm_cancel_cmd = CC.cruiseControl.cancel
|
|
||||||
|
|
||||||
# Steering Torque
|
# Steering Torque
|
||||||
new_steer = int(round(actuators.steer * self.params.STEER_MAX))
|
new_steer = int(round(actuators.steer * self.p.STEER_MAX))
|
||||||
apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.params)
|
apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.p)
|
||||||
self.steer_rate_limited = new_steer != apply_steer
|
self.steer_rate_limited = new_steer != apply_steer
|
||||||
|
|
||||||
if not CC.latActive:
|
if not c.latActive:
|
||||||
apply_steer = 0
|
apply_steer = 0
|
||||||
|
|
||||||
self.apply_steer_last = apply_steer
|
self.apply_steer_last = apply_steer
|
||||||
|
|
||||||
sys_warning, sys_state, left_lane_warning, right_lane_warning = process_hud_alert(CC.enabled, self.car_fingerprint,
|
sys_warning, sys_state, left_lane_warning, right_lane_warning = \
|
||||||
hud_control)
|
process_hud_alert(c.enabled, self.car_fingerprint, visual_alert,
|
||||||
|
left_lane, right_lane, left_lane_depart, right_lane_depart)
|
||||||
|
|
||||||
can_sends = []
|
can_sends = []
|
||||||
|
|
||||||
# tester present - w/ no response (keeps radar disabled)
|
# tester present - w/ no response (keeps radar disabled)
|
||||||
if self.CP.openpilotLongitudinalControl:
|
if CS.CP.openpilotLongitudinalControl:
|
||||||
if self.frame % 100 == 0:
|
if (frame % 100) == 0:
|
||||||
can_sends.append([0x7D0, 0, b"\x02\x3E\x80\x00\x00\x00\x00\x00", 0])
|
can_sends.append([0x7D0, 0, b"\x02\x3E\x80\x00\x00\x00\x00\x00", 0])
|
||||||
|
|
||||||
can_sends.append(create_lkas11(self.packer, self.frame, self.car_fingerprint, apply_steer, CC.latActive,
|
can_sends.append(create_lkas11(self.packer, frame, self.car_fingerprint, apply_steer, c.latActive,
|
||||||
CS.lkas11, sys_warning, sys_state, CC.enabled,
|
CS.lkas11, sys_warning, sys_state, c.enabled,
|
||||||
hud_control.leftLaneVisible, hud_control.rightLaneVisible,
|
left_lane, right_lane,
|
||||||
left_lane_warning, right_lane_warning))
|
left_lane_warning, right_lane_warning))
|
||||||
|
|
||||||
if not self.CP.openpilotLongitudinalControl:
|
if not CS.CP.openpilotLongitudinalControl:
|
||||||
if pcm_cancel_cmd:
|
if pcm_cancel_cmd:
|
||||||
can_sends.append(create_clu11(self.packer, self.frame, CS.clu11, Buttons.CANCEL))
|
can_sends.append(create_clu11(self.packer, frame, CS.clu11, Buttons.CANCEL))
|
||||||
elif CS.out.cruiseState.standstill:
|
elif CS.out.cruiseState.standstill:
|
||||||
# send resume at a max freq of 10Hz
|
# send resume at a max freq of 10Hz
|
||||||
if (self.frame - self.last_resume_frame) * DT_CTRL > 0.1:
|
if (frame - self.last_resume_frame) * DT_CTRL > 0.1:
|
||||||
# send 25 messages at a time to increases the likelihood of resume being accepted
|
# send 25 messages at a time to increases the likelihood of resume being accepted
|
||||||
can_sends.extend([create_clu11(self.packer, self.frame, CS.clu11, Buttons.RES_ACCEL)] * 25)
|
can_sends.extend([create_clu11(self.packer, frame, CS.clu11, Buttons.RES_ACCEL)] * 25)
|
||||||
self.last_resume_frame = self.frame
|
self.last_resume_frame = frame
|
||||||
|
|
||||||
if self.frame % 2 == 0 and self.CP.openpilotLongitudinalControl:
|
if frame % 2 == 0 and CS.CP.openpilotLongitudinalControl:
|
||||||
lead_visible = False
|
lead_visible = False
|
||||||
accel = actuators.accel if CC.longActive else 0
|
accel = actuators.accel if c.longActive else 0
|
||||||
|
|
||||||
jerk = clip(2.0 * (accel - CS.out.aEgo), -12.7, 12.7)
|
jerk = clip(2.0 * (accel - CS.out.aEgo), -12.7, 12.7)
|
||||||
|
|
||||||
|
@ -99,29 +96,27 @@ class CarController:
|
||||||
accel = clip(accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX)
|
accel = clip(accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX)
|
||||||
|
|
||||||
stopping = (actuators.longControlState == LongCtrlState.stopping)
|
stopping = (actuators.longControlState == LongCtrlState.stopping)
|
||||||
set_speed_in_units = hud_control.setSpeed * (CV.MS_TO_MPH if CS.clu11["CF_Clu_SPEED_UNIT"] == 1 else CV.MS_TO_KPH)
|
set_speed_in_units = hud_speed * (CV.MS_TO_MPH if CS.clu11["CF_Clu_SPEED_UNIT"] == 1 else CV.MS_TO_KPH)
|
||||||
can_sends.extend(create_acc_commands(self.packer, CC.enabled, accel, jerk, int(self.frame / 2), lead_visible,
|
can_sends.extend(create_acc_commands(self.packer, c.enabled, accel, jerk, int(frame / 2), lead_visible, set_speed_in_units, stopping))
|
||||||
set_speed_in_units, stopping, CS.out.gasPressed))
|
|
||||||
self.accel = accel
|
self.accel = accel
|
||||||
|
|
||||||
# 20 Hz LFA MFA message
|
# 20 Hz LFA MFA message
|
||||||
if self.frame % 5 == 0 and self.car_fingerprint in (CAR.SONATA, CAR.PALISADE, CAR.IONIQ, CAR.KIA_NIRO_EV, CAR.KIA_NIRO_HEV_2021,
|
if frame % 5 == 0 and self.car_fingerprint in (CAR.SONATA, CAR.PALISADE, CAR.IONIQ, CAR.KIA_NIRO_EV, CAR.KIA_NIRO_HEV_2021,
|
||||||
CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KIA_CEED, CAR.KIA_SELTOS, CAR.KONA_EV,
|
CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KIA_CEED, CAR.KIA_SELTOS, CAR.KONA_EV,
|
||||||
CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.SANTA_FE_2022,
|
CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.SANTA_FE_2022,
|
||||||
CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.GENESIS_G70_2020, CAR.SANTA_FE_PHEV_2022):
|
CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.GENESIS_G70_2020, CAR.SANTA_FE_PHEV_2022):
|
||||||
can_sends.append(create_lfahda_mfc(self.packer, CC.enabled))
|
can_sends.append(create_lfahda_mfc(self.packer, c.enabled))
|
||||||
|
|
||||||
# 5 Hz ACC options
|
# 5 Hz ACC options
|
||||||
if self.frame % 20 == 0 and self.CP.openpilotLongitudinalControl:
|
if frame % 20 == 0 and CS.CP.openpilotLongitudinalControl:
|
||||||
can_sends.extend(create_acc_opt(self.packer))
|
can_sends.extend(create_acc_opt(self.packer))
|
||||||
|
|
||||||
# 2 Hz front radar options
|
# 2 Hz front radar options
|
||||||
if self.frame % 50 == 0 and self.CP.openpilotLongitudinalControl:
|
if frame % 50 == 0 and CS.CP.openpilotLongitudinalControl:
|
||||||
can_sends.append(create_frt_radar_opt(self.packer))
|
can_sends.append(create_frt_radar_opt(self.packer))
|
||||||
|
|
||||||
new_actuators = actuators.copy()
|
new_actuators = actuators.copy()
|
||||||
new_actuators.steer = apply_steer / self.params.STEER_MAX
|
new_actuators.steer = apply_steer / self.p.STEER_MAX
|
||||||
new_actuators.accel = self.accel
|
new_actuators.accel = self.accel
|
||||||
|
|
||||||
self.frame += 1
|
|
||||||
return new_actuators, can_sends
|
return new_actuators, can_sends
|
||||||
|
|
|
@ -78,7 +78,7 @@ def create_lfahda_mfc(packer, enabled, hda_set_speed=0):
|
||||||
}
|
}
|
||||||
return packer.make_can_msg("LFAHDA_MFC", 0, values)
|
return packer.make_can_msg("LFAHDA_MFC", 0, values)
|
||||||
|
|
||||||
def create_acc_commands(packer, enabled, accel, jerk, idx, lead_visible, set_speed, stopping, gas_pressed):
|
def create_acc_commands(packer, enabled, accel, jerk, idx, lead_visible, set_speed, stopping):
|
||||||
commands = []
|
commands = []
|
||||||
|
|
||||||
scc11_values = {
|
scc11_values = {
|
||||||
|
@ -95,7 +95,7 @@ def create_acc_commands(packer, enabled, accel, jerk, idx, lead_visible, set_spe
|
||||||
commands.append(packer.make_can_msg("SCC11", 0, scc11_values))
|
commands.append(packer.make_can_msg("SCC11", 0, scc11_values))
|
||||||
|
|
||||||
scc12_values = {
|
scc12_values = {
|
||||||
"ACCMode": 2 if enabled and gas_pressed else 1 if enabled else 0,
|
"ACCMode": 1 if enabled else 0,
|
||||||
"StopReq": 1 if enabled and stopping else 0,
|
"StopReq": 1 if enabled and stopping else 0,
|
||||||
"aReqRaw": accel if enabled else 0,
|
"aReqRaw": accel if enabled else 0,
|
||||||
"aReqValue": accel if enabled else 0, # stock ramps up and down respecting jerk limit until it reaches aReqRaw
|
"aReqValue": accel if enabled else 0, # stock ramps up and down respecting jerk limit until it reaches aReqRaw
|
||||||
|
@ -111,7 +111,7 @@ def create_acc_commands(packer, enabled, accel, jerk, idx, lead_visible, set_spe
|
||||||
"ComfortBandLower": 0.0, # stock usually is 0 but sometimes uses higher values
|
"ComfortBandLower": 0.0, # stock usually is 0 but sometimes uses higher values
|
||||||
"JerkUpperLimit": max(jerk, 1.0) if (enabled and not stopping) else 0, # stock usually is 1.0 but sometimes uses higher values
|
"JerkUpperLimit": max(jerk, 1.0) if (enabled and not stopping) else 0, # stock usually is 1.0 but sometimes uses higher values
|
||||||
"JerkLowerLimit": max(-jerk, 1.0) if enabled else 0, # stock usually is 0.5 but sometimes uses higher values
|
"JerkLowerLimit": max(-jerk, 1.0) if enabled else 0, # stock usually is 0.5 but sometimes uses higher values
|
||||||
"ACCMode": 2 if enabled and gas_pressed else 1 if enabled else 4, # stock will always be 4 instead of 0 after first disengage
|
"ACCMode": 1 if enabled else 4, # stock will always be 4 instead of 0 after first disengage
|
||||||
"ObjGap": 2 if lead_visible else 0, # 5: >30, m, 4: 25-30 m, 3: 20-25 m, 2: < 20 m, 0: no lead
|
"ObjGap": 2 if lead_visible else 0, # 5: >30, m, 4: 25-30 m, 3: 20-25 m, 2: < 20 m, 0: no lead
|
||||||
}
|
}
|
||||||
commands.append(packer.make_can_msg("SCC14", 0, scc14_values))
|
commands.append(packer.make_can_msg("SCC14", 0, scc14_values))
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from cereal import car
|
from cereal import car
|
||||||
from panda import Panda
|
from panda import Panda
|
||||||
|
from common.params import Params
|
||||||
from common.conversions import Conversions as CV
|
from common.conversions import Conversions as CV
|
||||||
from selfdrive.car.hyundai.values import CAR, DBC, EV_CAR, HYBRID_CAR, LEGACY_SAFETY_MODE_CAR, Buttons, CarControllerParams
|
from selfdrive.car.hyundai.values import CAR, EV_CAR, HYBRID_CAR, LEGACY_SAFETY_MODE_CAR, Buttons, CarControllerParams
|
||||||
from selfdrive.car.hyundai.radar_interface import RADAR_START_ADDR
|
from selfdrive.car.hyundai.radar_interface import RADAR_START_ADDR
|
||||||
from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config
|
from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config
|
||||||
from selfdrive.car.interfaces import CarInterfaceBase
|
from selfdrive.car.interfaces import CarInterfaceBase
|
||||||
|
@ -17,15 +18,15 @@ class CarInterface(CarInterfaceBase):
|
||||||
return CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX
|
return CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=[], disable_radar=False): # pylint: disable=dangerous-default-value
|
def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=[]): # pylint: disable=dangerous-default-value
|
||||||
ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
|
ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
|
||||||
|
|
||||||
ret.carName = "hyundai"
|
ret.carName = "hyundai"
|
||||||
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.hyundai, 0)]
|
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.hyundai, 0)]
|
||||||
ret.radarOffCan = RADAR_START_ADDR not in fingerprint[1] or DBC[ret.carFingerprint]["radar"] is None
|
ret.radarOffCan = RADAR_START_ADDR not in fingerprint[1]
|
||||||
|
|
||||||
# WARNING: disabling radar also disables AEB (and we show the same warning on the instrument cluster as if you manually disabled AEB)
|
# WARNING: disabling radar also disables AEB (and we show the same warning on the instrument cluster as if you manually disabled AEB)
|
||||||
ret.openpilotLongitudinalControl = disable_radar and (candidate not in LEGACY_SAFETY_MODE_CAR)
|
ret.openpilotLongitudinalControl = Params().get_bool("DisableRadar") and (candidate not in LEGACY_SAFETY_MODE_CAR)
|
||||||
|
|
||||||
ret.pcmCruise = not ret.openpilotLongitudinalControl
|
ret.pcmCruise = not ret.openpilotLongitudinalControl
|
||||||
|
|
||||||
|
@ -348,5 +349,9 @@ class CarInterface(CarInterfaceBase):
|
||||||
return self.CS.out
|
return self.CS.out
|
||||||
|
|
||||||
def apply(self, c):
|
def apply(self, c):
|
||||||
ret = self.CC.update(c, self.CS)
|
hud_control = c.hudControl
|
||||||
|
ret = self.CC.update(c, self.CS, self.frame, c.actuators, c.cruiseControl.cancel, hud_control.visualAlert,
|
||||||
|
hud_control.setSpeed, hud_control.leftLaneVisible, hud_control.rightLaneVisible,
|
||||||
|
hud_control.leftLaneDepart, hud_control.rightLaneDepart)
|
||||||
|
self.frame += 1
|
||||||
return ret
|
return ret
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
from dataclasses import dataclass
|
|
||||||
from typing import Dict, List, Union
|
|
||||||
|
|
||||||
from cereal import car
|
from cereal import car
|
||||||
from common.conversions import Conversions as CV
|
|
||||||
from selfdrive.car import dbc_dict
|
from selfdrive.car import dbc_dict
|
||||||
from selfdrive.car.docs_definitions import CarInfo
|
|
||||||
Ecu = car.CarParams.Ecu
|
Ecu = car.CarParams.Ecu
|
||||||
|
|
||||||
# Steer torque limits
|
# Steer torque limits
|
||||||
|
@ -27,7 +22,6 @@ class CarControllerParams:
|
||||||
self.STEER_DRIVER_MULTIPLIER = 2
|
self.STEER_DRIVER_MULTIPLIER = 2
|
||||||
self.STEER_DRIVER_FACTOR = 1
|
self.STEER_DRIVER_FACTOR = 1
|
||||||
|
|
||||||
|
|
||||||
class CAR:
|
class CAR:
|
||||||
# Hyundai
|
# Hyundai
|
||||||
ELANTRA = "HYUNDAI ELANTRA 2017"
|
ELANTRA = "HYUNDAI ELANTRA 2017"
|
||||||
|
@ -73,60 +67,6 @@ class CAR:
|
||||||
GENESIS_G90 = "GENESIS G90 2017"
|
GENESIS_G90 = "GENESIS G90 2017"
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class HyundaiCarInfo(CarInfo):
|
|
||||||
package: str = "SCC + LKAS"
|
|
||||||
good_torque: bool = True
|
|
||||||
|
|
||||||
|
|
||||||
CAR_INFO: Dict[str, Union[HyundaiCarInfo, List[HyundaiCarInfo]]] = {
|
|
||||||
CAR.ELANTRA: HyundaiCarInfo("Hyundai Elantra 2017-19", min_enable_speed=19 * CV.MPH_TO_MS),
|
|
||||||
CAR.ELANTRA_2021: HyundaiCarInfo("Hyundai Elantra 2021-22", video_link="https://youtu.be/_EdYQtV52-c"),
|
|
||||||
CAR.ELANTRA_HEV_2021: HyundaiCarInfo("Hyundai Elantra Hybrid 2021", video_link="https://youtu.be/_EdYQtV52-c"),
|
|
||||||
CAR.HYUNDAI_GENESIS: HyundaiCarInfo("Hyundai Genesis 2015-16", min_enable_speed=19 * CV.MPH_TO_MS),
|
|
||||||
CAR.IONIQ: HyundaiCarInfo("Hyundai Ioniq Hybrid 2017-19"),
|
|
||||||
CAR.IONIQ_HEV_2022: HyundaiCarInfo("Hyundai Ioniq Hybrid 2020-22", "SCC + LFA"),
|
|
||||||
CAR.IONIQ_EV_LTD: HyundaiCarInfo("Hyundai Ioniq Electric 2019"),
|
|
||||||
CAR.IONIQ_EV_2020: HyundaiCarInfo("Hyundai Ioniq Electric 2020"),
|
|
||||||
CAR.IONIQ_PHEV: HyundaiCarInfo("Hyundai Ioniq Plug-In Hybrid 2020-21"),
|
|
||||||
CAR.KONA: HyundaiCarInfo("Hyundai Kona 2020"),
|
|
||||||
CAR.KONA_EV: HyundaiCarInfo("Hyundai Kona Electric 2018-19"),
|
|
||||||
CAR.KONA_HEV: HyundaiCarInfo("Hyundai Kona Hybrid 2020", video_link="https://youtu.be/_EdYQtV52-c"),
|
|
||||||
CAR.SANTA_FE: HyundaiCarInfo("Hyundai Santa Fe 2019-20", "All"),
|
|
||||||
CAR.SANTA_FE_2022: HyundaiCarInfo("Hyundai Santa Fe 2021-22", "All"),
|
|
||||||
CAR.SANTA_FE_HEV_2022: HyundaiCarInfo("Hyundai Santa Fe Hybrid 2022", "All"),
|
|
||||||
CAR.SANTA_FE_PHEV_2022: HyundaiCarInfo("Hyundai Santa Fe Plug-In Hybrid 2022", "All"),
|
|
||||||
CAR.SONATA: HyundaiCarInfo("Hyundai Sonata 2020-22", "All", video_link="https://www.youtube.com/watch?v=ix63r9kE3Fw"),
|
|
||||||
CAR.SONATA_LF: HyundaiCarInfo("Hyundai Sonata 2018-19"),
|
|
||||||
CAR.PALISADE: [
|
|
||||||
HyundaiCarInfo("Hyundai Palisade 2020-21", "All", video_link="https://youtu.be/TAnDqjF4fDY?t=456"),
|
|
||||||
HyundaiCarInfo("Kia Telluride 2020"),
|
|
||||||
],
|
|
||||||
CAR.VELOSTER: HyundaiCarInfo("Hyundai Veloster 2019-20", min_enable_speed=5. * CV.MPH_TO_MS),
|
|
||||||
CAR.SONATA_HYBRID: HyundaiCarInfo("Hyundai Sonata Hybrid 2021-22", "All"),
|
|
||||||
|
|
||||||
# Kia
|
|
||||||
CAR.KIA_FORTE: HyundaiCarInfo("Kia Forte 2018-21"),
|
|
||||||
CAR.KIA_K5_2021: HyundaiCarInfo("Kia K5 2021-22", "SCC + LFA"),
|
|
||||||
CAR.KIA_NIRO_EV: HyundaiCarInfo("Kia Niro Electric 2019-22", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo"),
|
|
||||||
CAR.KIA_NIRO_HEV: HyundaiCarInfo("Kia Niro Plug-In Hybrid 2019", min_enable_speed=10. * CV.MPH_TO_MS),
|
|
||||||
CAR.KIA_NIRO_HEV_2021: HyundaiCarInfo("Kia Niro Hybrid 2021-22"),
|
|
||||||
CAR.KIA_OPTIMA: [
|
|
||||||
HyundaiCarInfo("Kia Optima 2017", min_steer_speed=32. * CV.MPH_TO_MS),
|
|
||||||
HyundaiCarInfo("Kia Optima 2019"),
|
|
||||||
],
|
|
||||||
CAR.KIA_SELTOS: HyundaiCarInfo("Kia Seltos 2021"),
|
|
||||||
CAR.KIA_SORENTO: HyundaiCarInfo("Kia Sorento 2018-19", video_link="https://www.youtube.com/watch?v=Fkh3s6WHJz8"),
|
|
||||||
CAR.KIA_STINGER: HyundaiCarInfo("Kia Stinger 2018", video_link="https://www.youtube.com/watch?v=MJ94qoofYw0"),
|
|
||||||
CAR.KIA_CEED: HyundaiCarInfo("Kia Ceed 2019"),
|
|
||||||
|
|
||||||
# Genesis
|
|
||||||
CAR.GENESIS_G70: HyundaiCarInfo("Genesis G70 2018", "All"),
|
|
||||||
CAR.GENESIS_G70_2020: HyundaiCarInfo("Genesis G70 2020", "All"),
|
|
||||||
CAR.GENESIS_G80: HyundaiCarInfo("Genesis G80 2018", "All"),
|
|
||||||
CAR.GENESIS_G90: HyundaiCarInfo("Genesis G90 2018", "All"),
|
|
||||||
}
|
|
||||||
|
|
||||||
class Buttons:
|
class Buttons:
|
||||||
NONE = 0
|
NONE = 0
|
||||||
RES_ACCEL = 1
|
RES_ACCEL = 1
|
||||||
|
@ -753,12 +693,10 @@ FW_VERSIONS = {
|
||||||
CAR.GENESIS_G70_2020: {
|
CAR.GENESIS_G70_2020: {
|
||||||
(Ecu.eps, 0x7d4, None): [
|
(Ecu.eps, 0x7d4, None): [
|
||||||
b'\xf1\x00IK MDPS R 1.00 1.07 57700-G9220 4I2VL107',
|
b'\xf1\x00IK MDPS R 1.00 1.07 57700-G9220 4I2VL107',
|
||||||
b'\xf1\x00IK MDPS R 1.00 1.07 57700-G9420 4I4VL107',
|
|
||||||
],
|
],
|
||||||
(Ecu.transmission, 0x7e1, None): [
|
(Ecu.transmission, 0x7e1, None): [
|
||||||
b'\xf1\x87VCJLP18407832DN3\x88vXfvUVT\x97eFU\x87d7v\x88eVeveFU\x89\x98\x7f\xff\xb2\xb0\xf1\x81E25\x00\x00\x00',
|
b'\xf1\x87VCJLP18407832DN3\x88vXfvUVT\x97eFU\x87d7v\x88eVeveFU\x89\x98\x7f\xff\xb2\xb0\xf1\x81E25\x00\x00\x00',
|
||||||
b'\x00\x00\x00\x00\xf1\x00bcsh8p54 E25\x00\x00\x00\x00\x00\x00\x00SIK0T33NB4\xecE\xefL',
|
b'\x00\x00\x00\x00\xf1\x00bcsh8p54 E25\x00\x00\x00\x00\x00\x00\x00SIK0T33NB4\xecE\xefL',
|
||||||
b'\xf1\x87VDKLT18912362DN4wfVfwefeveVUwfvw\x88vWfvUFU\x89\xa9\x8f\xff\x87w\xf1\x81E25\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E25\x00\x00\x00\x00\x00\x00\x00SIK0T33NB4\xecE\xefL',
|
|
||||||
],
|
],
|
||||||
(Ecu.fwdRadar, 0x7d0, None): [
|
(Ecu.fwdRadar, 0x7d0, None): [
|
||||||
b'\xf1\x00IK__ SCC F-CUP 1.00 1.02 96400-G9100 ',
|
b'\xf1\x00IK__ SCC F-CUP 1.00 1.02 96400-G9100 ',
|
||||||
|
|
|
@ -50,7 +50,7 @@ class CarInterfaceBase(ABC):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None, disable_radar=False):
|
def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -75,6 +75,8 @@ class CarInterfaceBase(ABC):
|
||||||
|
|
||||||
# standard ALC params
|
# standard ALC params
|
||||||
ret.steerControlType = car.CarParams.SteerControlType.torque
|
ret.steerControlType = car.CarParams.SteerControlType.torque
|
||||||
|
ret.steerMaxBP = [0.]
|
||||||
|
ret.steerMaxV = [1.]
|
||||||
ret.minSteerSpeed = 0.
|
ret.minSteerSpeed = 0.
|
||||||
ret.wheelSpeedFactor = 1.0
|
ret.wheelSpeedFactor = 1.0
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ VisualAlert = car.CarControl.HUDControl.VisualAlert
|
||||||
|
|
||||||
class CarController():
|
class CarController():
|
||||||
def __init__(self, dbc_name, CP, VM):
|
def __init__(self, dbc_name, CP, VM):
|
||||||
self.CP = CP
|
|
||||||
self.apply_steer_last = 0
|
self.apply_steer_last = 0
|
||||||
self.packer = CANPacker(dbc_name)
|
self.packer = CANPacker(dbc_name)
|
||||||
self.steer_rate_limited = False
|
self.steer_rate_limited = False
|
||||||
|
@ -31,7 +30,7 @@ class CarController():
|
||||||
# Mazda Stop and Go requires a RES button (or gas) press if the car stops more than 3 seconds
|
# Mazda Stop and Go requires a RES button (or gas) press if the car stops more than 3 seconds
|
||||||
# Send Resume button at 20hz if we're engaged at standstill to support full stop and go!
|
# Send Resume button at 20hz if we're engaged at standstill to support full stop and go!
|
||||||
# TODO: improve the resume trigger logic by looking at actual radar data
|
# TODO: improve the resume trigger logic by looking at actual radar data
|
||||||
can_sends.append(mazdacan.create_button_cmd(self.packer, self.CP.carFingerprint, CS.crz_btns_counter, Buttons.RESUME))
|
can_sends.append(mazdacan.create_button_cmd(self.packer, CS.CP.carFingerprint, CS.crz_btns_counter, Buttons.RESUME))
|
||||||
|
|
||||||
if c.cruiseControl.cancel:
|
if c.cruiseControl.cancel:
|
||||||
# If brake is pressed, let us wait >70ms before trying to disable crz to avoid
|
# If brake is pressed, let us wait >70ms before trying to disable crz to avoid
|
||||||
|
@ -42,7 +41,7 @@ class CarController():
|
||||||
if frame % 10 == 0 and not (CS.out.brakePressed and self.brake_counter < 7):
|
if frame % 10 == 0 and not (CS.out.brakePressed and self.brake_counter < 7):
|
||||||
# Cancel Stock ACC if it's enabled while OP is disengaged
|
# Cancel Stock ACC if it's enabled while OP is disengaged
|
||||||
# Send at a rate of 10hz until we sync with stock ACC state
|
# Send at a rate of 10hz until we sync with stock ACC state
|
||||||
can_sends.append(mazdacan.create_button_cmd(self.packer, self.CP.carFingerprint, CS.crz_btns_counter, Buttons.CANCEL))
|
can_sends.append(mazdacan.create_button_cmd(self.packer, CS.CP.carFingerprint, CS.crz_btns_counter, Buttons.CANCEL))
|
||||||
else:
|
else:
|
||||||
self.brake_counter = 0
|
self.brake_counter = 0
|
||||||
|
|
||||||
|
@ -57,7 +56,7 @@ class CarController():
|
||||||
can_sends.append(mazdacan.create_alert_command(self.packer, CS.cam_laneinfo, ldw, steer_required))
|
can_sends.append(mazdacan.create_alert_command(self.packer, CS.cam_laneinfo, ldw, steer_required))
|
||||||
|
|
||||||
# send steering command
|
# send steering command
|
||||||
can_sends.append(mazdacan.create_steering_control(self.packer, self.CP.carFingerprint,
|
can_sends.append(mazdacan.create_steering_control(self.packer, CS.CP.carFingerprint,
|
||||||
frame, apply_steer, CS.cam_lkas))
|
frame, apply_steer, CS.cam_lkas))
|
||||||
|
|
||||||
new_actuators = c.actuators.copy()
|
new_actuators = c.actuators.copy()
|
||||||
|
|
|
@ -72,8 +72,6 @@ class CarState(CarStateBase):
|
||||||
self.lkas_allowed_speed = True
|
self.lkas_allowed_speed = True
|
||||||
elif speed_kph < LKAS_LIMITS.DISABLE_SPEED:
|
elif speed_kph < LKAS_LIMITS.DISABLE_SPEED:
|
||||||
self.lkas_allowed_speed = False
|
self.lkas_allowed_speed = False
|
||||||
else:
|
|
||||||
self.lkas_allowed_speed = True
|
|
||||||
|
|
||||||
# TODO: the signal used for available seems to be the adaptive cruise signal, instead of the main on
|
# TODO: the signal used for available seems to be the adaptive cruise signal, instead of the main on
|
||||||
# it should be used for carState.cruiseState.nonAdaptive instead
|
# it should be used for carState.cruiseState.nonAdaptive instead
|
||||||
|
|
|
@ -15,7 +15,7 @@ class CarInterface(CarInterfaceBase):
|
||||||
return float(accel) / 4.0
|
return float(accel) / 4.0
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None, disable_radar=False):
|
def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None):
|
||||||
ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
|
ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
|
||||||
|
|
||||||
ret.carName = "mazda"
|
ret.carName = "mazda"
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
from typing import Dict, List, Union
|
|
||||||
|
|
||||||
from selfdrive.car import dbc_dict
|
from selfdrive.car import dbc_dict
|
||||||
from selfdrive.car.docs_definitions import CarInfo
|
|
||||||
from cereal import car
|
from cereal import car
|
||||||
Ecu = car.CarParams.Ecu
|
Ecu = car.CarParams.Ecu
|
||||||
|
|
||||||
|
@ -17,7 +14,6 @@ class CarControllerParams:
|
||||||
STEER_DRIVER_FACTOR = 1 # from dbc
|
STEER_DRIVER_FACTOR = 1 # from dbc
|
||||||
STEER_ERROR_MAX = 350 # max delta between torque cmd and torque motor
|
STEER_ERROR_MAX = 350 # max delta between torque cmd and torque motor
|
||||||
|
|
||||||
|
|
||||||
class CAR:
|
class CAR:
|
||||||
CX5 = "MAZDA CX-5"
|
CX5 = "MAZDA CX-5"
|
||||||
CX9 = "MAZDA CX-9"
|
CX9 = "MAZDA CX-9"
|
||||||
|
@ -26,17 +22,6 @@ class CAR:
|
||||||
CX9_2021 = "MAZDA CX-9 2021"
|
CX9_2021 = "MAZDA CX-9 2021"
|
||||||
CX5_2022 = "MAZDA CX-5 2022"
|
CX5_2022 = "MAZDA CX-5 2022"
|
||||||
|
|
||||||
|
|
||||||
CAR_INFO: Dict[str, Union[CarInfo, List[CarInfo]]] = {
|
|
||||||
CAR.CX5: CarInfo("Mazda CX-5 2017, 2019", "All"), # TODO: verify years and torque for first 4
|
|
||||||
CAR.CX9: CarInfo("Mazda CX-9 2016-17", "All"),
|
|
||||||
CAR.MAZDA3: CarInfo("Mazda 3 2017", "All"),
|
|
||||||
CAR.MAZDA6: CarInfo("Mazda 6 2017", "All"),
|
|
||||||
CAR.CX9_2021: CarInfo("Mazda CX-9 2021", "All", good_torque=True),
|
|
||||||
CAR.CX5_2022: CarInfo("Mazda CX-5 2022", "All", good_torque=True),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class LKAS_LIMITS:
|
class LKAS_LIMITS:
|
||||||
STEER_THRESHOLD = 15
|
STEER_THRESHOLD = 15
|
||||||
DISABLE_SPEED = 45 # kph
|
DISABLE_SPEED = 45 # kph
|
||||||
|
|
|
@ -33,7 +33,7 @@ class CarInterface(CarInterfaceBase):
|
||||||
return accel
|
return accel
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None, disable_radar=False):
|
def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None):
|
||||||
ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
|
ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
|
||||||
ret.carName = "mock"
|
ret.carName = "mock"
|
||||||
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.noOutput)]
|
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.noOutput)]
|
||||||
|
|
|
@ -1,10 +1,2 @@
|
||||||
from typing import Dict, List, Union
|
|
||||||
|
|
||||||
from selfdrive.car.docs_definitions import CarInfo
|
|
||||||
|
|
||||||
|
|
||||||
class CAR:
|
class CAR:
|
||||||
MOCK = 'mock'
|
MOCK = 'mock'
|
||||||
|
|
||||||
|
|
||||||
CAR_INFO: Dict[str, Union[CarInfo, List[CarInfo]]] = {}
|
|
||||||
|
|
|
@ -58,14 +58,14 @@ class CarController():
|
||||||
self.last_angle = apply_angle
|
self.last_angle = apply_angle
|
||||||
|
|
||||||
if self.CP.carFingerprint in (CAR.ROGUE, CAR.XTRAIL, CAR.ALTIMA) and cruise_cancel:
|
if self.CP.carFingerprint in (CAR.ROGUE, CAR.XTRAIL, CAR.ALTIMA) and cruise_cancel:
|
||||||
can_sends.append(nissancan.create_acc_cancel_cmd(self.packer, self.car_fingerprint, CS.cruise_throttle_msg, frame))
|
can_sends.append(nissancan.create_acc_cancel_cmd(self.packer, self.car_fingerprint, CS.cruise_throttle_msg, frame))
|
||||||
|
|
||||||
# TODO: Find better way to cancel!
|
# TODO: Find better way to cancel!
|
||||||
# For some reason spamming the cancel button is unreliable on the Leaf
|
# For some reason spamming the cancel button is unreliable on the Leaf
|
||||||
# We now cancel by making propilot think the seatbelt is unlatched,
|
# We now cancel by making propilot think the seatbelt is unlatched,
|
||||||
# this generates a beep and a warning message every time you disengage
|
# this generates a beep and a warning message every time you disengage
|
||||||
if self.CP.carFingerprint in (CAR.LEAF, CAR.LEAF_IC) and frame % 2 == 0:
|
if self.CP.carFingerprint in (CAR.LEAF, CAR.LEAF_IC) and frame % 2 == 0:
|
||||||
can_sends.append(nissancan.create_cancel_msg(self.packer, CS.cancel_msg, cruise_cancel))
|
can_sends.append(nissancan.create_cancel_msg(self.packer, CS.cancel_msg, cruise_cancel))
|
||||||
|
|
||||||
can_sends.append(nissancan.create_steering_control(
|
can_sends.append(nissancan.create_steering_control(
|
||||||
self.packer, apply_angle, frame, c.enabled, self.lkas_max_torque))
|
self.packer, apply_angle, frame, c.enabled, self.lkas_max_torque))
|
||||||
|
|
|
@ -10,7 +10,7 @@ class CarInterface(CarInterfaceBase):
|
||||||
self.cp_adas = self.CS.get_adas_can_parser(CP)
|
self.cp_adas = self.CS.get_adas_can_parser(CP)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None, disable_radar=False):
|
def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None):
|
||||||
|
|
||||||
ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
|
ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
|
||||||
ret.carName = "nissan"
|
ret.carName = "nissan"
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
from typing import Dict, List, Union
|
|
||||||
|
|
||||||
from selfdrive.car import dbc_dict
|
from selfdrive.car import dbc_dict
|
||||||
from selfdrive.car.docs_definitions import CarInfo
|
|
||||||
from cereal import car
|
from cereal import car
|
||||||
Ecu = car.CarParams.Ecu
|
Ecu = car.CarParams.Ecu
|
||||||
|
|
||||||
|
@ -13,7 +10,6 @@ class CarControllerParams:
|
||||||
LKAS_MAX_TORQUE = 1 # A value of 1 is easy to overpower
|
LKAS_MAX_TORQUE = 1 # A value of 1 is easy to overpower
|
||||||
STEER_THRESHOLD = 1.0
|
STEER_THRESHOLD = 1.0
|
||||||
|
|
||||||
|
|
||||||
class CAR:
|
class CAR:
|
||||||
XTRAIL = "NISSAN X-TRAIL 2017"
|
XTRAIL = "NISSAN X-TRAIL 2017"
|
||||||
LEAF = "NISSAN LEAF 2018"
|
LEAF = "NISSAN LEAF 2018"
|
||||||
|
@ -24,13 +20,6 @@ class CAR:
|
||||||
ALTIMA = "NISSAN ALTIMA 2020"
|
ALTIMA = "NISSAN ALTIMA 2020"
|
||||||
|
|
||||||
|
|
||||||
CAR_INFO: Dict[str, Union[CarInfo, List[CarInfo]]] = {
|
|
||||||
CAR.XTRAIL: CarInfo("Nissan X-Trail 2017", "ProPILOT"),
|
|
||||||
CAR.LEAF: CarInfo("Nissan Leaf 2018-22", "ProPILOT"),
|
|
||||||
CAR.ROGUE: CarInfo("Nissan Rogue 2018-20", "ProPILOT"),
|
|
||||||
CAR.ALTIMA: CarInfo("Nissan Altima 2019-20", "ProPILOT"),
|
|
||||||
}
|
|
||||||
|
|
||||||
FINGERPRINTS = {
|
FINGERPRINTS = {
|
||||||
CAR.XTRAIL: [
|
CAR.XTRAIL: [
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,7 +6,6 @@ from opendbc.can.packer import CANPacker
|
||||||
|
|
||||||
class CarController():
|
class CarController():
|
||||||
def __init__(self, dbc_name, CP, VM):
|
def __init__(self, dbc_name, CP, VM):
|
||||||
self.CP = CP
|
|
||||||
self.apply_steer_last = 0
|
self.apply_steer_last = 0
|
||||||
self.es_distance_cnt = -1
|
self.es_distance_cnt = -1
|
||||||
self.es_lkas_cnt = -1
|
self.es_lkas_cnt = -1
|
||||||
|
@ -34,7 +33,7 @@ class CarController():
|
||||||
if not c.latActive:
|
if not c.latActive:
|
||||||
apply_steer = 0
|
apply_steer = 0
|
||||||
|
|
||||||
if self.CP.carFingerprint in PREGLOBAL_CARS:
|
if CS.CP.carFingerprint in PREGLOBAL_CARS:
|
||||||
can_sends.append(subarucan.create_preglobal_steering_control(self.packer, apply_steer, frame, self.p.STEER_STEP))
|
can_sends.append(subarucan.create_preglobal_steering_control(self.packer, apply_steer, frame, self.p.STEER_STEP))
|
||||||
else:
|
else:
|
||||||
can_sends.append(subarucan.create_steering_control(self.packer, apply_steer, frame, self.p.STEER_STEP))
|
can_sends.append(subarucan.create_steering_control(self.packer, apply_steer, frame, self.p.STEER_STEP))
|
||||||
|
@ -44,7 +43,7 @@ class CarController():
|
||||||
|
|
||||||
# *** alerts and pcm cancel ***
|
# *** alerts and pcm cancel ***
|
||||||
|
|
||||||
if self.CP.carFingerprint in PREGLOBAL_CARS:
|
if CS.CP.carFingerprint in PREGLOBAL_CARS:
|
||||||
if self.es_distance_cnt != CS.es_distance_msg["Counter"]:
|
if self.es_distance_cnt != CS.es_distance_msg["Counter"]:
|
||||||
# 1 = main, 2 = set shallow, 3 = set deep, 4 = resume shallow, 5 = resume deep
|
# 1 = main, 2 = set shallow, 3 = set deep, 4 = resume shallow, 5 = resume deep
|
||||||
# disengage ACC when OP is disengaged
|
# disengage ACC when OP is disengaged
|
||||||
|
|
|
@ -7,7 +7,7 @@ from selfdrive.car.interfaces import CarInterfaceBase
|
||||||
class CarInterface(CarInterfaceBase):
|
class CarInterface(CarInterfaceBase):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None, disable_radar=False):
|
def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None):
|
||||||
ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
|
ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
|
||||||
|
|
||||||
ret.carName = "subaru"
|
ret.carName = "subaru"
|
||||||
|
|
|
@ -54,7 +54,7 @@ def create_es_lkas(packer, es_lkas_msg, enabled, visual_alert, left_line, right_
|
||||||
values["LKAS_ACTIVE"] = 1 # Show LKAS lane lines
|
values["LKAS_ACTIVE"] = 1 # Show LKAS lane lines
|
||||||
values["LKAS_Dash_State"] = 2 # Green enabled indicator
|
values["LKAS_Dash_State"] = 2 # Green enabled indicator
|
||||||
else:
|
else:
|
||||||
values["LKAS_Dash_State"] = 0 # LKAS Not enabled
|
values["LKAS_Dash_State"] = 0 # LKAS Not enabled
|
||||||
|
|
||||||
values["LKAS_Left_Line_Visible"] = int(left_line)
|
values["LKAS_Left_Line_Visible"] = int(left_line)
|
||||||
values["LKAS_Right_Line_Visible"] = int(right_line)
|
values["LKAS_Right_Line_Visible"] = int(right_line)
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
from typing import Dict, List, Union
|
|
||||||
|
|
||||||
from selfdrive.car import dbc_dict
|
from selfdrive.car import dbc_dict
|
||||||
from selfdrive.car.docs_definitions import CarInfo
|
|
||||||
from cereal import car
|
from cereal import car
|
||||||
Ecu = car.CarParams.Ecu
|
Ecu = car.CarParams.Ecu
|
||||||
|
|
||||||
|
@ -18,7 +15,6 @@ class CarControllerParams:
|
||||||
self.STEER_DRIVER_MULTIPLIER = 10 # weight driver torque heavily
|
self.STEER_DRIVER_MULTIPLIER = 10 # weight driver torque heavily
|
||||||
self.STEER_DRIVER_FACTOR = 1 # from dbc
|
self.STEER_DRIVER_FACTOR = 1 # from dbc
|
||||||
|
|
||||||
|
|
||||||
class CAR:
|
class CAR:
|
||||||
ASCENT = "SUBARU ASCENT LIMITED 2019"
|
ASCENT = "SUBARU ASCENT LIMITED 2019"
|
||||||
IMPREZA = "SUBARU IMPREZA LIMITED 2019"
|
IMPREZA = "SUBARU IMPREZA LIMITED 2019"
|
||||||
|
@ -29,21 +25,6 @@ class CAR:
|
||||||
OUTBACK_PREGLOBAL = "SUBARU OUTBACK 2015 - 2017"
|
OUTBACK_PREGLOBAL = "SUBARU OUTBACK 2015 - 2017"
|
||||||
OUTBACK_PREGLOBAL_2018 = "SUBARU OUTBACK 2018 - 2019"
|
OUTBACK_PREGLOBAL_2018 = "SUBARU OUTBACK 2018 - 2019"
|
||||||
|
|
||||||
|
|
||||||
CAR_INFO: Dict[str, Union[CarInfo, List[CarInfo]]] = {
|
|
||||||
CAR.ASCENT: CarInfo("Subaru Ascent 2019", "EyeSight"),
|
|
||||||
CAR.IMPREZA: [
|
|
||||||
CarInfo("Subaru Impreza 2017-19", "EyeSight"),
|
|
||||||
CarInfo("Subaru Crosstrek 2018-20", "EyeSight"),
|
|
||||||
],
|
|
||||||
CAR.FORESTER: CarInfo("Subaru Forester 2019-21", "EyeSight"),
|
|
||||||
CAR.FORESTER_PREGLOBAL: CarInfo("Subaru Forester 2017-18", "EyeSight"),
|
|
||||||
CAR.LEGACY_PREGLOBAL: CarInfo("Subaru Legacy 2015-18", "EyeSight"),
|
|
||||||
CAR.OUTBACK_PREGLOBAL: CarInfo("Subaru Outback 2015-17", "EyeSight"),
|
|
||||||
CAR.OUTBACK_PREGLOBAL_2018: CarInfo("Subaru Outback 2018-19", "EyeSight"),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
FINGERPRINTS = {
|
FINGERPRINTS = {
|
||||||
CAR.IMPREZA_2020: [{
|
CAR.IMPREZA_2020: [{
|
||||||
2: 8, 64: 8, 65: 8, 72: 8, 73: 8, 280: 8, 281: 8, 282: 8, 290: 8, 312: 8, 313: 8, 314: 8, 315: 8, 316: 8, 326: 8, 372: 8, 544: 8, 545: 8, 546: 8, 552: 8, 554: 8, 557: 8, 576: 8, 577: 8, 722: 8, 801: 8, 802: 8, 803: 8, 805: 8, 808: 8, 816: 8, 826: 8, 837: 8, 838: 8, 839: 8, 842: 8, 912: 8, 915: 8, 940: 8, 1617: 8, 1632: 8, 1650: 8, 1677: 8, 1697: 8, 1722: 8, 1743: 8, 1759: 8, 1786: 5, 1787: 5, 1788: 8, 1809: 8, 1813: 8, 1817: 8, 1821: 8, 1840: 8, 1848: 8, 1924: 8, 1932: 8, 1952: 8, 1960: 8, 1968: 8, 1976: 8, 2015: 8, 2016: 8, 2024: 8
|
2: 8, 64: 8, 65: 8, 72: 8, 73: 8, 280: 8, 281: 8, 282: 8, 290: 8, 312: 8, 313: 8, 314: 8, 315: 8, 316: 8, 326: 8, 372: 8, 544: 8, 545: 8, 546: 8, 552: 8, 554: 8, 557: 8, 576: 8, 577: 8, 722: 8, 801: 8, 802: 8, 803: 8, 805: 8, 808: 8, 816: 8, 826: 8, 837: 8, 838: 8, 839: 8, 842: 8, 912: 8, 915: 8, 940: 8, 1617: 8, 1632: 8, 1650: 8, 1677: 8, 1697: 8, 1722: 8, 1743: 8, 1759: 8, 1786: 5, 1787: 5, 1788: 8, 1809: 8, 1813: 8, 1817: 8, 1821: 8, 1840: 8, 1848: 8, 1924: 8, 1932: 8, 1952: 8, 1960: 8, 1968: 8, 1976: 8, 2015: 8, 2016: 8, 2024: 8
|
||||||
|
|
|
@ -44,7 +44,7 @@ class CarState(CarStateBase):
|
||||||
ret.steeringTorque = -cp.vl["EPAS_sysStatus"]["EPAS_torsionBarTorque"]
|
ret.steeringTorque = -cp.vl["EPAS_sysStatus"]["EPAS_torsionBarTorque"]
|
||||||
ret.steeringPressed = (self.hands_on_level > 0)
|
ret.steeringPressed = (self.hands_on_level > 0)
|
||||||
ret.steerFaultPermanent = steer_status == "EAC_FAULT"
|
ret.steerFaultPermanent = steer_status == "EAC_FAULT"
|
||||||
ret.steerFaultTemporary = (self.steer_warning not in ("EAC_ERROR_IDLE", "EAC_ERROR_HANDS_ON"))
|
ret.steerFaultTemporary = self.steer_warning != "EAC_ERROR_IDLE"
|
||||||
|
|
||||||
# Cruise state
|
# Cruise state
|
||||||
cruise_state = self.can_define.dv["DI_state"]["DI_cruiseState"].get(int(cp.vl["DI_state"]["DI_cruiseState"]), None)
|
cruise_state = self.can_define.dv["DI_state"]["DI_cruiseState"].get(int(cp.vl["DI_state"]["DI_cruiseState"]), None)
|
||||||
|
|