mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-08-21 22:13:45 +08:00
Merge remote-tracking branch 'upstream/master' into palisade-2023-port-1
This commit is contained in:
Executable → Regular
@@ -1,4 +1,4 @@
|
||||
name: repo
|
||||
name: repo maintenance
|
||||
|
||||
on:
|
||||
schedule:
|
||||
@@ -6,13 +6,17 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
pre-commit-autoupdate:
|
||||
name: pre-commit autoupdate
|
||||
updates:
|
||||
name: updates
|
||||
runs-on: ubuntu-20.04
|
||||
container:
|
||||
image: ghcr.io/commaai/openpilot-base:latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: poetry lock
|
||||
run: |
|
||||
pip install poetry
|
||||
poetry lock
|
||||
- name: pre-commit autoupdate
|
||||
run: |
|
||||
git config --global --add safe.directory '*'
|
||||
@@ -21,8 +25,8 @@ jobs:
|
||||
uses: peter-evans/create-pull-request@5b4a9f6a9e2af26e5f02351490b90d01eb8ec1e5
|
||||
with:
|
||||
token: ${{ secrets.ACTIONS_CREATE_PR_PAT }}
|
||||
commit-message: Update pre-commit hook versions
|
||||
title: 'pre-commit: autoupdate hooks'
|
||||
branch: pre-commit-updates
|
||||
commit-message: Update Python packages and pre-commit hooks
|
||||
title: 'Update Python packages and pre-commit hooks'
|
||||
branch: auto-package-updates
|
||||
base: master
|
||||
delete-branch: true
|
||||
@@ -26,6 +26,7 @@ env:
|
||||
RUN_CL: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e PYTHONWARNINGS=error -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $CL_BASE_IMAGE /bin/sh -c
|
||||
|
||||
UNIT_TEST: coverage run --append -m unittest discover
|
||||
PYTEST: pytest --continue-on-collection-errors --cov --cov-report=xml --cov-append --durations=0 --durations-min=5
|
||||
|
||||
jobs:
|
||||
build_release:
|
||||
@@ -248,23 +249,9 @@ jobs:
|
||||
timeout-minutes: 40
|
||||
run: |
|
||||
${{ env.RUN }} "export SKIP_LONG_TESTS=1 && \
|
||||
$UNIT_TEST common && \
|
||||
$UNIT_TEST opendbc/can && \
|
||||
$UNIT_TEST selfdrive/boardd && \
|
||||
$UNIT_TEST selfdrive/controls && \
|
||||
$UNIT_TEST selfdrive/monitoring && \
|
||||
$UNIT_TEST system/loggerd && \
|
||||
$UNIT_TEST selfdrive/car && \
|
||||
$UNIT_TEST selfdrive/locationd && \
|
||||
$UNIT_TEST selfdrive/test/longitudinal_maneuvers && \
|
||||
$UNIT_TEST system/tests && \
|
||||
$UNIT_TEST system/ubloxd && \
|
||||
$PYTEST && \
|
||||
selfdrive/locationd/test/_test_locationd_lib.py && \
|
||||
./system/ubloxd/tests/test_glonass_runner && \
|
||||
$UNIT_TEST selfdrive/athena && \
|
||||
$UNIT_TEST selfdrive/thermald && \
|
||||
$UNIT_TEST system/hardware/tici && \
|
||||
$UNIT_TEST tools/lib/tests && \
|
||||
./selfdrive/ui/tests/create_test_translations.sh && \
|
||||
QT_QPA_PLATFORM=offscreen ./selfdrive/ui/tests/test_translations && \
|
||||
./selfdrive/ui/tests/test_translations.py && \
|
||||
@@ -275,8 +262,7 @@ jobs:
|
||||
./tools/replay/tests/test_replay && \
|
||||
./tools/cabana/tests/test_cabana && \
|
||||
./system/camerad/test/ae_gray_test && \
|
||||
./selfdrive/test/process_replay/test_fuzzy.py && \
|
||||
coverage xml"
|
||||
./selfdrive/test/process_replay/test_fuzzy.py"
|
||||
- name: "Upload coverage to Codecov"
|
||||
uses: codecov/codecov-action@v3
|
||||
|
||||
@@ -375,7 +361,7 @@ jobs:
|
||||
- name: Test car models
|
||||
timeout-minutes: 25
|
||||
run: |
|
||||
${{ env.RUN }} "pytest --cov --cov-report=xml -n auto --dist=loadscope selfdrive/car/tests/test_models.py && \
|
||||
${{ env.RUN }} "$PYTEST -n auto --dist=loadscope selfdrive/car/tests/test_models.py && \
|
||||
chmod -R 777 /tmp/comma_download_cache"
|
||||
env:
|
||||
NUM_JOBS: 5
|
||||
|
||||
@@ -33,11 +33,10 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
- name: Build Docker image
|
||||
run: eval "$BUILD"
|
||||
- uses: ./.github/workflows/setup
|
||||
- name: Build openpilot
|
||||
timeout-minutes: 5
|
||||
run: ${{ env.RUN }} "scons -j$(nproc) --directory=/tmp/openpilot/cereal --minimal"
|
||||
run: ${{ env.RUN }} "scons -j$(nproc) cereal/ common/ --minimal"
|
||||
- name: Test PlotJuggler
|
||||
timeout-minutes: 2
|
||||
run: |
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
exclude: '^(tinygrad_repo)'
|
||||
repos:
|
||||
- repo: meta
|
||||
hooks:
|
||||
@@ -14,6 +15,8 @@ repos:
|
||||
- id: check-yaml
|
||||
- id: check-merge-conflict
|
||||
- id: check-symlinks
|
||||
- id: check-executables-have-shebangs
|
||||
- id: check-shebang-scripts-are-executable
|
||||
- id: check-added-large-files
|
||||
args: ['--maxkb=100']
|
||||
- repo: https://github.com/codespell-project/codespell
|
||||
@@ -35,7 +38,7 @@ repos:
|
||||
args: ['--explicit-package-bases']
|
||||
exclude: '^(third_party/)|(cereal/)|(opendbc/)|(panda/)|(laika/)|(laika_repo/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(xx/)'
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.0.285
|
||||
rev: v0.0.287
|
||||
hooks:
|
||||
- id: ruff
|
||||
exclude: '^(third_party/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(laika_repo/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)'
|
||||
|
||||
+1
-1
Submodule cereal updated: 82bca3a971...d469732b3b
Executable → Regular
@@ -2,11 +2,11 @@ import os
|
||||
import shutil
|
||||
import uuid
|
||||
|
||||
from typing import List, Optional
|
||||
from typing import Optional
|
||||
|
||||
from openpilot.common.params import Params
|
||||
|
||||
class OpenpilotPrefix(object):
|
||||
class OpenpilotPrefix:
|
||||
def __init__(self, prefix: Optional[str] = None, clean_dirs_on_exit: bool = True):
|
||||
self.prefix = prefix if prefix else str(uuid.uuid4())
|
||||
self.msgq_path = os.path.join('/dev/shm', self.prefix)
|
||||
@@ -24,7 +24,10 @@ class OpenpilotPrefix(object):
|
||||
def __exit__(self, exc_type, exc_obj, exc_tb):
|
||||
if self.clean_dirs_on_exit:
|
||||
self.clean_dirs()
|
||||
del os.environ['OPENPILOT_PREFIX']
|
||||
try:
|
||||
del os.environ['OPENPILOT_PREFIX']
|
||||
except KeyError:
|
||||
pass
|
||||
return False
|
||||
|
||||
def clean_dirs(self):
|
||||
@@ -33,17 +36,3 @@ class OpenpilotPrefix(object):
|
||||
shutil.rmtree(os.path.realpath(symlink_path), ignore_errors=True)
|
||||
os.remove(symlink_path)
|
||||
shutil.rmtree(self.msgq_path, ignore_errors=True)
|
||||
|
||||
|
||||
class DummySocket:
|
||||
def __init__(self):
|
||||
self.data: List[bytes] = []
|
||||
|
||||
def receive(self, non_blocking: bool = False) -> Optional[bytes]:
|
||||
if non_blocking:
|
||||
return None
|
||||
|
||||
return self.data.pop()
|
||||
|
||||
def send(self, data: bytes):
|
||||
self.data.append(data)
|
||||
@@ -1,8 +1,6 @@
|
||||
import os
|
||||
import threading
|
||||
import time
|
||||
import tempfile
|
||||
import shutil
|
||||
import uuid
|
||||
import unittest
|
||||
|
||||
@@ -10,12 +8,7 @@ from openpilot.common.params import Params, ParamKeyType, UnknownKeyName, put_no
|
||||
|
||||
class TestParams(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.tmpdir = tempfile.mkdtemp()
|
||||
print("using", self.tmpdir)
|
||||
self.params = Params(self.tmpdir)
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self.tmpdir)
|
||||
self.params = Params()
|
||||
|
||||
def test_params_put_and_get(self):
|
||||
self.params.put("DongleId", "cb38263377b873ee")
|
||||
@@ -90,19 +83,19 @@ class TestParams(unittest.TestCase):
|
||||
self.assertFalse(self.params.get_bool("IsMetric"))
|
||||
|
||||
def test_put_non_blocking_with_get_block(self):
|
||||
q = Params(self.tmpdir)
|
||||
q = Params()
|
||||
def _delayed_writer():
|
||||
time.sleep(0.1)
|
||||
put_nonblocking("CarParams", "test", self.tmpdir)
|
||||
put_nonblocking("CarParams", "test")
|
||||
threading.Thread(target=_delayed_writer).start()
|
||||
assert q.get("CarParams") is None
|
||||
assert q.get("CarParams", True) == b"test"
|
||||
|
||||
def test_put_bool_non_blocking_with_get_block(self):
|
||||
q = Params(self.tmpdir)
|
||||
q = Params()
|
||||
def _delayed_writer():
|
||||
time.sleep(0.1)
|
||||
put_bool_nonblocking("CarParams", True, self.tmpdir)
|
||||
put_bool_nonblocking("CarParams", True)
|
||||
threading.Thread(target=_delayed_writer).start()
|
||||
assert q.get("CarParams") is None
|
||||
assert q.get("CarParams", True) == b"1"
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import pytest
|
||||
|
||||
from openpilot.common.prefix import OpenpilotPrefix
|
||||
|
||||
|
||||
@pytest.fixture(scope="function", autouse=True)
|
||||
def global_setup_and_teardown():
|
||||
# setup a clean environment for each test
|
||||
with OpenpilotPrefix():
|
||||
yield
|
||||
+5
-5
@@ -2,7 +2,7 @@
|
||||
|
||||
# Supported Cars
|
||||
|
||||
A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. Supported vehicles reference the US market unless otherwise specified.
|
||||
A supported vehicle is one that just works when you install a comma device. All supported cars provide a better experience than any stock system. Supported vehicles reference the US market unless otherwise specified.
|
||||
|
||||
# 262 Supported Cars
|
||||
|
||||
@@ -83,14 +83,14 @@ A supported vehicle is one that just works when you install a comma three. All s
|
||||
|Hyundai|Ioniq 6 (with HDA II) 2023[<sup>6</sup>](#footnotes)|Highway Driving Assist II|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 6 (with HDA II) 2023">Buy Here</a></sub></details>||
|
||||
|Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Electric 2019">Buy Here</a></sub></details>||
|
||||
|Hyundai|Ioniq Electric 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Electric 2020">Buy Here</a></sub></details>||
|
||||
|Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Hybrid 2017-19">Buy Here</a></sub></details>||
|
||||
|Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Hybrid 2017-19">Buy Here</a></sub></details>||
|
||||
|Hyundai|Ioniq Hybrid 2020-22|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Hybrid 2020-22">Buy Here</a></sub></details>||
|
||||
|Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Plug-in Hybrid 2019">Buy Here</a></sub></details>||
|
||||
|Hyundai|Ioniq Plug-in Hybrid 2020-22|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Plug-in Hybrid 2020-22">Buy Here</a></sub></details>||
|
||||
|Hyundai|Ioniq Plug-in Hybrid 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Plug-in Hybrid 2020-22">Buy Here</a></sub></details>||
|
||||
|Hyundai|Kona 2020|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Kona 2020">Buy Here</a></sub></details>||
|
||||
|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Kona Electric 2018-21">Buy Here</a></sub></details>||
|
||||
|Hyundai|Kona Electric 2022|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai O connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Kona Electric 2022">Buy Here</a></sub></details>||
|
||||
|Hyundai|Kona Electric (with HDA II, Korea only) 2023[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai R connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Kona Electric (with HDA II, Korea only) 2023">Buy Here</a></sub></details>||
|
||||
|Hyundai|Kona Electric (with HDA II, Korea only) 2023[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai R connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Kona Electric (with HDA II, Korea only) 2023">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=U2fOCmcQ8hw" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai I connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Kona Hybrid 2020">Buy Here</a></sub></details>|<a href="https://youtu.be/0dwpAHiZgFo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Hyundai|Palisade 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Palisade 2020-22">Buy Here</a></sub></details>|<a href="https://youtu.be/TAnDqjF4fDY?t=456" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Hyundai|Palisade (with HDA II) 2023-24|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai R connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma power v2<br>- 1 comma three<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Palisade (with HDA II) 2023-24">Buy Here</a></sub></details>||
|
||||
@@ -188,7 +188,7 @@ A supported vehicle is one that just works when you install a comma three. All s
|
||||
|Škoda|Kamiq 2021[<sup>9,11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Kamiq 2021">Buy Here</a></sub></details>[<sup>13</sup>](#footnotes)||
|
||||
|Škoda|Karoq 2019-23[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Karoq 2019-23">Buy Here</a></sub></details>||
|
||||
|Škoda|Kodiaq 2017-23[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Kodiaq 2017-23">Buy Here</a></sub></details>||
|
||||
|Škoda|Octavia 2015, 2018-19[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Octavia 2015, 2018-19">Buy Here</a></sub></details>||
|
||||
|Škoda|Octavia 2015-19[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Octavia 2015-19">Buy Here</a></sub></details>||
|
||||
|Škoda|Octavia RS 2016[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Octavia RS 2016">Buy Here</a></sub></details>||
|
||||
|Škoda|Scala 2020-23[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Scala 2020-23">Buy Here</a></sub></details>[<sup>13</sup>](#footnotes)||
|
||||
|Škoda|Superb 2015-22[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma three<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Superb 2015-22">Buy Here</a></sub></details>||
|
||||
|
||||
+1
-1
Submodule laika_repo updated: c9baa95ca9...8861844c9b
+1
-1
Submodule opendbc updated: e400fbd84e...e9458174da
+1
-1
Submodule panda updated: a159d98f57...5b98671669
Generated
+1194
-508
File diff suppressed because it is too large
Load Diff
+18
-1
@@ -1,11 +1,27 @@
|
||||
[tool.pytest.ini_options]
|
||||
minversion = "6.0"
|
||||
addopts = "--ignore=openpilot/ --ignore=opendbc/ --ignore=panda/ --ignore=rednose_repo/ --ignore=tinygrad_repo/ --ignore=laika_repo/ -Werror --strict-config --strict-markers"
|
||||
addopts = "--ignore=openpilot/ --ignore=cereal/ --ignore=opendbc/ --ignore=panda/ --ignore=rednose_repo/ --ignore=tinygrad_repo/ --ignore=laika_repo/ -Werror --strict-config --strict-markers"
|
||||
python_files = "test_*.py"
|
||||
#timeout = "30" # you get this long by default
|
||||
markers = [
|
||||
"parallel: mark tests as parallelizable (tests with no global state, so can be run in parallel)"
|
||||
]
|
||||
testpaths = [
|
||||
"common",
|
||||
"selfdrive/athena",
|
||||
"selfdrive/boardd",
|
||||
"selfdrive/car",
|
||||
"selfdrive/controls",
|
||||
"selfdrive/locationd",
|
||||
"selfdrive/monitoring",
|
||||
"selfdrive/thermald",
|
||||
"selfdrive/test/longitudinal_maneuvers",
|
||||
"system/hardware/tici",
|
||||
"system/loggerd",
|
||||
"system/tests",
|
||||
"system/ubloxd",
|
||||
"tools/lib/tests"
|
||||
]
|
||||
|
||||
[tool.mypy]
|
||||
python_version = "3.11"
|
||||
@@ -112,6 +128,7 @@ inputs = "*"
|
||||
lru-dict = "*"
|
||||
markdown-it-py = "*"
|
||||
matplotlib = "*"
|
||||
metadrive-simulator = { git = "https://github.com/metadriverse/metadrive.git", rev ="51d4393f3b3574fd0e79ed04eae0081f8447ca72" }
|
||||
mpld3 = "*"
|
||||
mypy = "*"
|
||||
myst-parser = "*"
|
||||
|
||||
+1
-1
Submodule rednose_repo updated: e32658ed91...8658bed296
@@ -48,6 +48,7 @@ class TestAthenadMethods(unittest.TestCase):
|
||||
else:
|
||||
os.unlink(p)
|
||||
|
||||
dispatcher["listUploadQueue"]() # ensure queue is empty at start
|
||||
|
||||
# *** test helpers ***
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
# Supported Cars
|
||||
|
||||
A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. Supported vehicles reference the US market unless otherwise specified.
|
||||
A supported vehicle is one that just works when you install a comma device. All supported cars provide a better experience than any stock system. Supported vehicles reference the US market unless otherwise specified.
|
||||
|
||||
# {{all_car_info | length}} Supported Cars
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ def create_button_events(cur_btn: int, prev_btn: int, buttons_dict: Dict[int, ca
|
||||
|
||||
|
||||
def gen_empty_fingerprint():
|
||||
return {i: {} for i in range(0, 8)}
|
||||
return {i: {} for i in range(8)}
|
||||
|
||||
|
||||
# these params were derived for the Civic and used to calculate params for other cars
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#!/usr/bin/env python3
|
||||
import math
|
||||
from cereal import car
|
||||
from openpilot.common.realtime import DT_CTRL
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#!/usr/bin/env python3
|
||||
from openpilot.selfdrive.car.interfaces import RadarInterfaceBase
|
||||
|
||||
class RadarInterface(RadarInterfaceBase):
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
from openpilot.selfdrive.car.isotp_parallel_query import IsoTpParallelQuery
|
||||
from openpilot.system.swaglog import cloudlog
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#!/usr/bin/env python3
|
||||
from cereal import car
|
||||
from panda import Panda
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#!/usr/bin/env python3
|
||||
from math import cos, sin
|
||||
from cereal import car
|
||||
from opendbc.can.parser import CANParser
|
||||
|
||||
@@ -265,6 +265,7 @@ FW_VERSIONS = {
|
||||
b'NZ6A-14C204-AAA\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||
b'NZ6A-14C204-PA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||
b'NZ6A-14C204-ZA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||
b'PZ6A-14C204-BE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||
b'PZ6A-14C204-JC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||
],
|
||||
},
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#!/usr/bin/env python3
|
||||
from cereal import car
|
||||
from panda import Panda
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#!/usr/bin/env python3
|
||||
import math
|
||||
|
||||
from cereal import car
|
||||
|
||||
@@ -183,7 +183,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = {
|
||||
CAR.KONA_EV_2022: HyundaiCarInfo("Hyundai Kona Electric 2022", car_parts=CarParts.common([CarHarness.hyundai_o])),
|
||||
CAR.KONA_HEV: HyundaiCarInfo("Hyundai Kona Hybrid 2020", video_link="https://youtu.be/0dwpAHiZgFo",
|
||||
car_parts=CarParts.common([CarHarness.hyundai_i])), # TODO: check packages
|
||||
CAR.KONA_EV_2ND_GEN: HyundaiCarInfo("Hyundai Kona Electric (with HDA II, Korea only) 2023", car_parts=CarParts.common([CarHarness.hyundai_r])),
|
||||
CAR.KONA_EV_2ND_GEN: HyundaiCarInfo("Hyundai Kona Electric (with HDA II, Korea only) 2023", video_link="https://www.youtube.com/watch?v=U2fOCmcQ8hw", car_parts=CarParts.common([CarHarness.hyundai_r])),
|
||||
CAR.SANTA_FE: HyundaiCarInfo("Hyundai Santa Fe 2019-20", "All", car_parts=CarParts.common([CarHarness.hyundai_d])),
|
||||
CAR.SANTA_FE_2022: HyundaiCarInfo("Hyundai Santa Fe 2021-23", "All", video_link="https://youtu.be/VnHzSTygTS4",
|
||||
car_parts=CarParts.common([CarHarness.hyundai_l])),
|
||||
@@ -587,11 +587,13 @@ FW_VERSIONS = {
|
||||
b'\xf1\x00AE MDPS C 1.00 1.01 56310/G2510 4APHC101',
|
||||
b'\xf1\x00AE MDPS C 1.00 1.01 56310/G2560 4APHC101',
|
||||
b'\xf1\x00AE MDPS C 1.00 1.01 56310G2510\x00 4APHC101',
|
||||
b'\xf1\x00AE MDPS C 1.00 1.01 56310/G2310 4APHC101',
|
||||
],
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00AEP MFC AT USA LHD 1.00 1.01 95740-G2600 190819',
|
||||
b'\xf1\x00AEP MFC AT EUR RHD 1.00 1.01 95740-G2600 190819',
|
||||
b'\xf1\x00AEP MFC AT USA LHD 1.00 1.00 95740-G2700 201027',
|
||||
b'\xf1\x00AEP MFC AT EUR LHD 1.00 1.01 95740-G2600 190819',
|
||||
],
|
||||
(Ecu.engine, 0x7e0, None): [
|
||||
b'\xf1\x816H6F6051\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||
@@ -604,6 +606,7 @@ FW_VERSIONS = {
|
||||
b'\xf1\x816U3J9051\x00\x00\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00PAE0G16NL2\x00\x00\x00\x00',
|
||||
b'\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00PAE0G16NL0\x00\x00\x00\x00',
|
||||
b'\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00PAE0G16NL2\xad\xeb\xabt',
|
||||
b'\xf1\x006U3H1_C2\x00\x006U3J8051\x00\x00PAETG16UL0\x00\x00\x00\x00',
|
||||
],
|
||||
},
|
||||
CAR.IONIQ_EV_2020: {
|
||||
@@ -1941,6 +1944,7 @@ FW_VERSIONS = {
|
||||
CAR.KIA_SORENTO_HEV_4TH_GEN: {
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00MQ4HMFC AT KOR LHD 1.00 1.12 99210-P2000 230331',
|
||||
b'\xf1\x00MQ4HMFC AT USA LHD 1.00 1.11 99210-P2000 211217',
|
||||
],
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00MQhe SCC FHCUP 1.00 1.07 99110-P4000 ',
|
||||
@@ -2004,7 +2008,7 @@ EV_CAR = {CAR.IONIQ_EV_2020, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.KIA_NIRO_EV, CAR
|
||||
CAR.KIA_EV6, CAR.IONIQ_5, CAR.IONIQ_6, CAR.GENESIS_GV60_EV_1ST_GEN, CAR.KONA_EV_2ND_GEN}
|
||||
|
||||
# these cars require a special panda safety mode due to missing counters and checksums in the messages
|
||||
LEGACY_SAFETY_MODE_CAR = {CAR.HYUNDAI_GENESIS, CAR.IONIQ_EV_LTD, CAR.IONIQ_PHEV, CAR.IONIQ, CAR.KONA_EV, CAR.KIA_OPTIMA_G4,
|
||||
LEGACY_SAFETY_MODE_CAR = {CAR.HYUNDAI_GENESIS, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.KIA_OPTIMA_G4,
|
||||
CAR.VELOSTER, CAR.GENESIS_G70, CAR.GENESIS_G80, CAR.KIA_CEED, CAR.ELANTRA, CAR.IONIQ_HEV_2022,
|
||||
CAR.KIA_OPTIMA_H}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
from cereal import car
|
||||
from panda import Panda
|
||||
from openpilot.selfdrive.car import get_safety_config
|
||||
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
|
||||
from openpilot.selfdrive.car.nissan.values import CAR
|
||||
@@ -31,7 +31,7 @@ class CarInterface(CarInterfaceBase):
|
||||
ret.centerToFront = ret.wheelbase * 0.44
|
||||
elif candidate == CAR.ALTIMA:
|
||||
# Altima has EPS on C-CAN unlike the others that have it on V-CAN
|
||||
ret.safetyConfigs[0].safetyParam = 1 # EPS is on alternate bus
|
||||
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_NISSAN_ALT_EPS_BUS
|
||||
ret.mass = 1492
|
||||
ret.wheelbase = 2.824
|
||||
ret.centerToFront = ret.wheelbase * 0.44
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#!/usr/bin/env python3
|
||||
from openpilot.selfdrive.car.interfaces import RadarInterfaceBase
|
||||
|
||||
class RadarInterface(RadarInterfaceBase):
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#!/usr/bin/env python3
|
||||
from cereal import car
|
||||
from panda import Panda
|
||||
from openpilot.selfdrive.car import get_safety_config
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#!/usr/bin/env python3
|
||||
from openpilot.selfdrive.car.interfaces import RadarInterfaceBase
|
||||
|
||||
class RadarInterface(RadarInterfaceBase):
|
||||
|
||||
@@ -310,6 +310,7 @@ FW_VERSIONS = {
|
||||
b'\xa2 !`\000',
|
||||
b'\xf1\x00\xb2\x06\x04',
|
||||
b'\xa2 `\x00',
|
||||
b'\xa2 !3\x00',
|
||||
],
|
||||
(Ecu.eps, 0x746, None): [
|
||||
b'\x9a\xc0\000\000',
|
||||
@@ -323,6 +324,7 @@ FW_VERSIONS = {
|
||||
b'\x00\x00eq\x1f@ "',
|
||||
b'\x00\x00eq\x00\x00\x00\x00',
|
||||
b'\x00\x00e\x8f\x00\x00\x00\x00',
|
||||
b'\x00\x00e\xa4\x00\x00\x00\x00',
|
||||
],
|
||||
(Ecu.engine, 0x7e0, None): [
|
||||
b'\xca!ap\a',
|
||||
@@ -337,6 +339,7 @@ FW_VERSIONS = {
|
||||
b'\xf3"fp\x07',
|
||||
b'\xe6"f0\x07',
|
||||
b'\xe6"fp\x07',
|
||||
b'\xe6!`@\x07',
|
||||
],
|
||||
(Ecu.transmission, 0x7e1, None): [
|
||||
b'\xe6\xf5\004\000\000',
|
||||
@@ -348,6 +351,7 @@ FW_VERSIONS = {
|
||||
b'\xe9\xf6F0\x00',
|
||||
b'\xe9\xf5B0\x00',
|
||||
b'\xe9\xf6B0\x00',
|
||||
b'\xe9\xf5"\x00\x00',
|
||||
],
|
||||
},
|
||||
CAR.CROSSTREK_HYBRID: {
|
||||
|
||||
Regular → Executable
+4
@@ -127,9 +127,11 @@ routes = [
|
||||
CarTestRoute("eb4eae1476647463|2023-08-26--18-07-04", HYUNDAI.IONIQ_6, segment=6), # HDA2
|
||||
CarTestRoute("3f29334d6134fcd4|2022-03-30--22-00-50", HYUNDAI.IONIQ_PHEV_2019),
|
||||
CarTestRoute("fa8db5869167f821|2021-06-10--22-50-10", HYUNDAI.IONIQ_PHEV),
|
||||
CarTestRoute("e1107f9d04dfb1e2|2023-09-05--22-32-12", HYUNDAI.IONIQ_PHEV), # openpilot longitudinal enabled
|
||||
CarTestRoute("2c5cf2dd6102e5da|2020-12-17--16-06-44", HYUNDAI.IONIQ_EV_2020),
|
||||
CarTestRoute("610ebb9faaad6b43|2020-06-13--15-28-36", HYUNDAI.IONIQ_EV_LTD),
|
||||
CarTestRoute("2c5cf2dd6102e5da|2020-06-26--16-00-08", HYUNDAI.IONIQ),
|
||||
CarTestRoute("012c95f06918eca4|2023-01-15--11-19-36", HYUNDAI.IONIQ), # openpilot longitudinal enabled
|
||||
CarTestRoute("ab59fe909f626921|2021-10-18--18-34-28", HYUNDAI.IONIQ_HEV_2022),
|
||||
CarTestRoute("22d955b2cd499c22|2020-08-10--19-58-21", HYUNDAI.KONA),
|
||||
CarTestRoute("efc48acf44b1e64d|2021-05-28--21-05-04", HYUNDAI.KONA_EV),
|
||||
@@ -167,6 +169,7 @@ routes = [
|
||||
CarTestRoute("e9966711cfb04ce3|2022-01-11--07-59-43", TOYOTA.AVALON_TSS2),
|
||||
CarTestRoute("eca1080a91720a54|2022-03-17--13-32-29", TOYOTA.AVALONH_TSS2),
|
||||
CarTestRoute("6cdecc4728d4af37|2020-02-23--15-44-18", TOYOTA.CAMRY),
|
||||
CarTestRoute("2f37c007683e85ba|2023-09-02--14-39-44", TOYOTA.CAMRY), # openpilot longitudinal, with radar CAN filter
|
||||
CarTestRoute("3456ad0cd7281b24|2020-12-13--17-45-56", TOYOTA.CAMRY_TSS2),
|
||||
CarTestRoute("ffccc77938ddbc44|2021-01-04--16-55-41", TOYOTA.CAMRYH_TSS2),
|
||||
CarTestRoute("54034823d30962f5|2021-05-24--06-37-34", TOYOTA.CAMRYH),
|
||||
@@ -207,6 +210,7 @@ routes = [
|
||||
CarTestRoute("ea8fbe72b96a185c|2023-02-22--09-20-34", TOYOTA.CHR_TSS2), # openpilot longitudinal, with smartDSU
|
||||
CarTestRoute("57858ede0369a261|2021-05-18--20-34-20", TOYOTA.CHRH),
|
||||
CarTestRoute("6719965b0e1d1737|2023-02-09--22-44-05", TOYOTA.CHRH_TSS2),
|
||||
# CarTestRoute("6719965b0e1d1737|2023-08-29--06-40-05", TOYOTA.CHRH_TSS2), # openpilot longitudinal, radar disabled
|
||||
CarTestRoute("14623aae37e549f3|2021-10-24--01-20-49", TOYOTA.PRIUS_V),
|
||||
|
||||
CarTestRoute("202c40641158a6e5|2021-09-21--09-43-24", VOLKSWAGEN.ARTEON_MK1),
|
||||
|
||||
@@ -175,7 +175,7 @@ class TestFwFingerprint(unittest.TestCase):
|
||||
|
||||
class TestFwFingerprintTiming(unittest.TestCase):
|
||||
N: int = 5
|
||||
TOL: float = 0.1
|
||||
TOL: float = 0.12
|
||||
|
||||
@staticmethod
|
||||
def _run_thread(thread: threading.Thread) -> float:
|
||||
|
||||
@@ -21,8 +21,10 @@ from openpilot.tools.lib.logreader import LogReader
|
||||
from openpilot.tools.lib.route import Route, SegmentName, RouteName
|
||||
|
||||
from panda.tests.libpanda import libpanda_py
|
||||
from openpilot.selfdrive.test.helpers import SKIP_ENV_VAR
|
||||
|
||||
PandaType = log.PandaState.PandaType
|
||||
SafetyModel = car.CarParams.SafetyModel
|
||||
|
||||
NUM_JOBS = int(os.environ.get("NUM_JOBS", "1"))
|
||||
JOB_ID = int(os.environ.get("JOB_ID", "0"))
|
||||
@@ -62,8 +64,6 @@ def get_test_cases() -> List[Tuple[str, Optional[CarTestRoute]]]:
|
||||
return test_cases
|
||||
|
||||
|
||||
SKIP_ENV_VAR = "SKIP_LONG_TESTS"
|
||||
|
||||
|
||||
class TestCarModelBase(unittest.TestCase):
|
||||
car_model: Optional[str] = None
|
||||
@@ -71,6 +71,7 @@ class TestCarModelBase(unittest.TestCase):
|
||||
ci: bool = True
|
||||
|
||||
can_msgs: List[capnp.lib.capnp._DynamicStructReader]
|
||||
elm_frame: Optional[int]
|
||||
|
||||
@unittest.skipIf(SKIP_ENV_VAR in os.environ, f"Long running test skipped. Unset {SKIP_ENV_VAR} to run")
|
||||
@classmethod
|
||||
@@ -106,6 +107,7 @@ class TestCarModelBase(unittest.TestCase):
|
||||
|
||||
car_fw = []
|
||||
can_msgs = []
|
||||
cls.elm_frame = None
|
||||
fingerprint = defaultdict(dict)
|
||||
experimental_long = False
|
||||
enabled_toggle = True
|
||||
@@ -131,6 +133,16 @@ class TestCarModelBase(unittest.TestCase):
|
||||
if param.key == 'OpenpilotEnabledToggle':
|
||||
enabled_toggle = param.value.strip(b'\x00') == b'1'
|
||||
|
||||
# Log which can frame the panda safety mode left ELM327, for CAN validity checks
|
||||
if msg.which() == 'pandaStates':
|
||||
for ps in msg.pandaStates:
|
||||
if cls.elm_frame is None and ps.safetyModel != SafetyModel.elm327:
|
||||
cls.elm_frame = len(can_msgs)
|
||||
|
||||
elif msg.which() == 'pandaStateDEPRECATED':
|
||||
if cls.elm_frame is None and msg.pandaStateDEPRECATED.safetyModel != SafetyModel.elm327:
|
||||
cls.elm_frame = len(can_msgs)
|
||||
|
||||
if len(can_msgs) > int(50 / DT_CTRL):
|
||||
break
|
||||
else:
|
||||
@@ -205,8 +217,10 @@ class TestCarModelBase(unittest.TestCase):
|
||||
RI = RadarInterface(self.CP)
|
||||
assert RI
|
||||
|
||||
# Since OBD port is multiplexed to bus 1 (commonly radar bus) while fingerprinting,
|
||||
# start parsing CAN messages after we've left ELM mode and can expect CAN traffic
|
||||
error_cnt = 0
|
||||
for i, msg in enumerate(self.can_msgs):
|
||||
for i, msg in enumerate(self.can_msgs[self.elm_frame:]):
|
||||
rr = RI.update((msg.as_builder().to_bytes(),))
|
||||
if rr is not None and i > 50:
|
||||
error_cnt += car.RadarData.Error.canError in rr.errors
|
||||
@@ -239,9 +253,9 @@ class TestCarModelBase(unittest.TestCase):
|
||||
if t > 1e6:
|
||||
self.assertTrue(self.safety.addr_checks_valid())
|
||||
|
||||
# No need to check relay malfunction on disabled routes (relay closed) or for reasonable fingerprinting time
|
||||
# TODO: detect when relay has flipped to properly check relay malfunction
|
||||
if self.openpilot_enabled and t > 5e6:
|
||||
# No need to check relay malfunction on disabled routes (relay closed),
|
||||
# or before fingerprinting is done (1s of tolerance to exit silent mode)
|
||||
if self.openpilot_enabled and t / 1e4 > (self.elm_frame + 100):
|
||||
self.assertFalse(self.safety.get_relay_malfunction())
|
||||
else:
|
||||
self.safety.set_relay_malfunction(False)
|
||||
|
||||
@@ -210,7 +210,7 @@ class CarState(CarStateBase):
|
||||
("PCS_HUD", 1),
|
||||
]
|
||||
|
||||
if CP.carFingerprint not in (TSS2_CAR - RADAR_ACC_CAR) and not CP.enableDsu:
|
||||
if CP.carFingerprint not in (TSS2_CAR - RADAR_ACC_CAR) and not CP.enableDsu and not CP.flags & ToyotaFlags.DISABLE_RADAR.value:
|
||||
messages += [
|
||||
("PRE_COLLISION", 33),
|
||||
]
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#!/usr/bin/env python3
|
||||
from cereal import car
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
from panda import Panda
|
||||
@@ -205,7 +204,8 @@ class CarInterface(CarInterfaceBase):
|
||||
ret.enableBsm = 0x3F6 in fingerprint[0] and candidate in TSS2_CAR
|
||||
|
||||
# Detect smartDSU, which intercepts ACC_CMD from the DSU (or radar) allowing openpilot to send it
|
||||
if 0x2FF in fingerprint[0]:
|
||||
# 0x2AA is sent by a similar device which intercepts the radar instead of DSU on NO_DSU_CARs
|
||||
if 0x2FF in fingerprint[0] or (0x2AA in fingerprint[0] and candidate in NO_DSU_CAR):
|
||||
ret.flags |= ToyotaFlags.SMART_DSU.value
|
||||
|
||||
# No radar dbc for cars without DSU which are not TSS 2.0
|
||||
@@ -219,13 +219,14 @@ class CarInterface(CarInterfaceBase):
|
||||
ret.enableGasInterceptor = 0x201 in fingerprint[0]
|
||||
|
||||
# if the smartDSU is detected, openpilot can send ACC_CONTROL and the smartDSU will block it from the DSU or radar.
|
||||
# since we don't yet parse radar on TSS2 radar-based ACC cars, gate longitudinal behind experimental toggle
|
||||
# since we don't yet parse radar on TSS2/TSS-P radar-based ACC cars, gate longitudinal behind experimental toggle
|
||||
use_sdsu = bool(ret.flags & ToyotaFlags.SMART_DSU)
|
||||
if candidate in RADAR_ACC_CAR:
|
||||
if candidate in (RADAR_ACC_CAR | NO_DSU_CAR):
|
||||
ret.experimentalLongitudinalAvailable = use_sdsu
|
||||
|
||||
if not use_sdsu:
|
||||
if experimental_long and False: # TODO: disabling radar isn't supported yet
|
||||
# Disabling radar is only supported on TSS2 radar-ACC cars
|
||||
if experimental_long and candidate in RADAR_ACC_CAR and False: # TODO: disabling radar isn't supported yet
|
||||
ret.flags |= ToyotaFlags.DISABLE_RADAR.value
|
||||
else:
|
||||
use_sdsu = use_sdsu and experimental_long
|
||||
@@ -237,6 +238,7 @@ class CarInterface(CarInterfaceBase):
|
||||
# openpilot longitudinal behind experimental long toggle:
|
||||
# - TSS2 radar ACC cars w/ smartDSU installed
|
||||
# - TSS2 radar ACC cars w/o smartDSU installed (disables radar)
|
||||
# - TSS-P DSU-less cars w/ CAN filter installed (no radar parser yet)
|
||||
ret.openpilotLongitudinalControl = use_sdsu or ret.enableDsu or candidate in (TSS2_CAR - RADAR_ACC_CAR) or bool(ret.flags & ToyotaFlags.DISABLE_RADAR.value)
|
||||
ret.autoResumeSng = ret.openpilotLongitudinalControl and candidate in NO_STOP_TIMER_CAR
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#!/usr/bin/env python3
|
||||
from openpilot.selfdrive.car.interfaces import RadarInterfaceBase
|
||||
|
||||
class RadarInterface(RadarInterfaceBase):
|
||||
|
||||
Executable → Regular
+7
-2
@@ -265,7 +265,7 @@ CAR_INFO: Dict[str, Union[VWCarInfo, List[VWCarInfo]]] = {
|
||||
CAR.SKODA_SCALA_MK1: VWCarInfo("Škoda Scala 2020-23", footnotes=[Footnote.VW_MQB_A0]),
|
||||
CAR.SKODA_SUPERB_MK3: VWCarInfo("Škoda Superb 2015-22"),
|
||||
CAR.SKODA_OCTAVIA_MK3: [
|
||||
VWCarInfo("Škoda Octavia 2015, 2018-19"),
|
||||
VWCarInfo("Škoda Octavia 2015-19"),
|
||||
VWCarInfo("Škoda Octavia RS 2016"),
|
||||
],
|
||||
}
|
||||
@@ -1254,6 +1254,7 @@ FW_VERSIONS = {
|
||||
b'\xf1\x8704E906027HD\xf1\x893742',
|
||||
b'\xf1\x8704E906027MH\xf1\x894786',
|
||||
b'\xf1\x8704L906021DT\xf1\x898127',
|
||||
b'\xf1\x8704L906026BP\xf1\x897608',
|
||||
b'\xf1\x8704L906026BS\xf1\x891541',
|
||||
b'\xf1\x875G0906259C \xf1\x890002',
|
||||
],
|
||||
@@ -1263,11 +1264,13 @@ FW_VERSIONS = {
|
||||
b'\xf1\x870CW300043B \xf1\x891601',
|
||||
b'\xf1\x870CW300043P \xf1\x891605',
|
||||
b'\xf1\x870D9300041C \xf1\x894936',
|
||||
b'\xf1\x870D9300041H \xf1\x895220',
|
||||
b'\xf1\x870D9300041J \xf1\x894902',
|
||||
b'\xf1\x870D9300041P \xf1\x894507',
|
||||
],
|
||||
(Ecu.srs, 0x715, None): [
|
||||
b'\xf1\x873Q0959655AC\xf1\x890200\xf1\x82\r11120011100010022212110200',
|
||||
b'\xf1\x873Q0959655AP\xf1\x890305\xf1\x82\r11110011110011213331312131',
|
||||
b'\xf1\x873Q0959655AQ\xf1\x890200\xf1\x82\r11120011100010312212113100',
|
||||
b'\xf1\x873Q0959655AS\xf1\x890200\xf1\x82\r11120011100010022212110200',
|
||||
b'\xf1\x873Q0959655BH\xf1\x890703\xf1\x82\0163221003221002105755331052100',
|
||||
@@ -1279,13 +1282,15 @@ FW_VERSIONS = {
|
||||
b'\xf1\x873Q0909144J \xf1\x895063\xf1\x82\00566A01513A1',
|
||||
b'\xf1\x875Q0909144AA\xf1\x891081\xf1\x82\00521T00403A1',
|
||||
b'\xf1\x875Q0909144AB\xf1\x891082\xf1\x82\x0521T00403A1',
|
||||
b'\xf1\x875QD909144E \xf1\x891081\xf1\x82\x0521T00503A1',
|
||||
b'\xf1\x875Q0909144R \xf1\x891061\xf1\x82\x0516A00604A1',
|
||||
b'\xf1\x875Q0909144T \xf1\x891072\xf1\x82\x0521T00601A1',
|
||||
b'\xf1\x875QD909144E \xf1\x891081\xf1\x82\x0521T00503A1',
|
||||
],
|
||||
(Ecu.fwdRadar, 0x757, None): [
|
||||
b'\xf1\x875Q0907572D \xf1\x890304\xf1\x82\x0101',
|
||||
b'\xf1\x875Q0907572F \xf1\x890400\xf1\x82\00101',
|
||||
b'\xf1\x875Q0907572J \xf1\x890654',
|
||||
b'\xf1\x875Q0907572K \xf1\x890402\xf1\x82\x0101',
|
||||
b'\xf1\x875Q0907572P \xf1\x890682',
|
||||
b'\xf1\x875Q0907572R \xf1\x890771',
|
||||
],
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
import math
|
||||
import os
|
||||
from enum import IntEnum
|
||||
|
||||
Regular → Executable
+1
-1
@@ -290,7 +290,7 @@ class LongitudinalMpc:
|
||||
self.x0[1] = v
|
||||
self.x0[2] = a
|
||||
if abs(v_prev - v) > 2.: # probably only helps if v < v_prev
|
||||
for i in range(0, N+1):
|
||||
for i in range(N+1):
|
||||
self.solver.set(i, 'x', self.x0)
|
||||
|
||||
@staticmethod
|
||||
|
||||
Regular → Executable
+15
-13
@@ -1,5 +1,8 @@
|
||||
#!/usr/bin/env python3
|
||||
import unittest
|
||||
import itertools
|
||||
from parameterized import parameterized_class
|
||||
|
||||
from openpilot.common.params import Params
|
||||
from cereal import log
|
||||
|
||||
@@ -23,22 +26,21 @@ def run_following_distance_simulation(v_lead, t_end=100.0, e2e=False):
|
||||
return output[-1,2] - output[-1,1]
|
||||
|
||||
|
||||
@parameterized_class(("e2e", "personality", "speed"), itertools.product(
|
||||
[True, False], # e2e
|
||||
[log.LongitudinalPersonality.relaxed, # personality
|
||||
log.LongitudinalPersonality.standard,
|
||||
log.LongitudinalPersonality.aggressive],
|
||||
[0,10,35])) # speed
|
||||
class TestFollowingDistance(unittest.TestCase):
|
||||
def test_following_distance(self):
|
||||
params = Params()
|
||||
personalities = [log.LongitudinalPersonality.relaxed,
|
||||
log.LongitudinalPersonality.standard,
|
||||
log.LongitudinalPersonality.aggressive]
|
||||
for personality in personalities:
|
||||
params.put("LongitudinalPersonality", str(personality))
|
||||
for e2e in [False, True]:
|
||||
for speed in [0,10,35]:
|
||||
print(f'Testing {speed} m/s')
|
||||
v_lead = float(speed)
|
||||
simulation_steady_state = run_following_distance_simulation(v_lead, e2e=e2e)
|
||||
correct_steady_state = desired_follow_distance(v_lead, v_lead, get_T_FOLLOW(personality))
|
||||
err_ratio = 0.2 if e2e else 0.1
|
||||
self.assertAlmostEqual(simulation_steady_state, correct_steady_state, delta=(err_ratio * correct_steady_state + .5))
|
||||
params.put("LongitudinalPersonality", str(self.personality))
|
||||
v_lead = float(self.speed)
|
||||
simulation_steady_state = run_following_distance_simulation(v_lead, e2e=self.e2e)
|
||||
correct_steady_state = desired_follow_distance(v_lead, v_lead, get_T_FOLLOW(self.personality))
|
||||
err_ratio = 0.2 if self.e2e else 0.1
|
||||
self.assertAlmostEqual(simulation_steady_state, correct_steady_state, delta=(err_ratio * correct_steady_state + .5))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Regular → Executable
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import time
|
||||
import unittest
|
||||
from cereal import log
|
||||
@@ -18,6 +19,7 @@ from openpilot.selfdrive.test.openpilotci import get_url
|
||||
from openpilot.tools.lib.logreader import LogReader
|
||||
|
||||
from openpilot.selfdrive.test.process_replay.process_replay import get_process_config, replay_process
|
||||
from openpilot.selfdrive.test.helpers import SKIP_ENV_VAR
|
||||
|
||||
GPS_TIME_PREDICTION_ORBITS_RUSSIAN_SRC = GPSTime.from_datetime(datetime(2022, month=1, day=29, hour=12))
|
||||
UBLOX_TEST_ROUTE = "4cf7a6ad03080c90|2021-09-29--13-46-36"
|
||||
@@ -92,6 +94,7 @@ def get_measurement_mock(gpstime, sat_ephemeris):
|
||||
return meas
|
||||
|
||||
|
||||
@unittest.skipIf(SKIP_ENV_VAR in os.environ, f"Laika test skipped since it's long and not currently used. Unset {SKIP_ENV_VAR} to run")
|
||||
class TestLaikad(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -80,7 +80,7 @@ class TestLocationdProc(unittest.TestCase):
|
||||
for msg in sorted(msgs, key=lambda x: x.logMonoTime):
|
||||
self.pm.send(msg.which(), msg)
|
||||
if msg.which() == "cameraOdometry":
|
||||
self.pm.wait_for_readers_to_update(msg.which(), 0.1)
|
||||
self.pm.wait_for_readers_to_update(msg.which(), 0.1, dt=0.005)
|
||||
time.sleep(1) # wait for async params write
|
||||
|
||||
lastGPS = json.loads(self.params.get('LastGPSPosition'))
|
||||
|
||||
@@ -44,6 +44,10 @@ for pathdef, fn in {'TRANSFORM': 'transforms/transform.cl', 'LOADYUV': 'transfor
|
||||
xenv['CXXFLAGS'].append(f'-D{pathdef}_PATH=\\"{File(fn).abspath}\\"')
|
||||
|
||||
# Compile cython
|
||||
snpe_rpath_qcom = "/data/pythonpath/third_party/snpe/larch64"
|
||||
snpe_rpath_pc = f"{Dir('#').abspath}/third_party/snpe/x86_64-linux-clang"
|
||||
snpe_rpath = lenvCython['RPATH'] + [snpe_rpath_qcom if arch == "larch64" else snpe_rpath_pc]
|
||||
|
||||
cython_libs = envCython["LIBS"] + libs
|
||||
onnxmodel_lib = lenv.Library('onnxmodel', ['runners/onnxmodel.cc'])
|
||||
snpemodel_lib = lenv.Library('snpemodel', ['runners/snpemodel.cc'])
|
||||
@@ -52,7 +56,7 @@ driving_lib = lenv.Library('driving', ['models/driving.cc'])
|
||||
|
||||
lenvCython.Program('runners/runmodel_pyx.so', 'runners/runmodel_pyx.pyx', LIBS=cython_libs, FRAMEWORKS=frameworks)
|
||||
lenvCython.Program('runners/onnxmodel_pyx.so', 'runners/onnxmodel_pyx.pyx', LIBS=[onnxmodel_lib, *cython_libs], FRAMEWORKS=frameworks)
|
||||
lenvCython.Program('runners/snpemodel_pyx.so', 'runners/snpemodel_pyx.pyx', LIBS=[snpemodel_lib, snpe_lib, *cython_libs], FRAMEWORKS=frameworks)
|
||||
lenvCython.Program('runners/snpemodel_pyx.so', 'runners/snpemodel_pyx.pyx', LIBS=[snpemodel_lib, snpe_lib, *cython_libs], FRAMEWORKS=frameworks, RPATH=snpe_rpath)
|
||||
lenvCython.Program('models/commonmodel_pyx.so', 'models/commonmodel_pyx.pyx', LIBS=[commonmodel_lib, *cython_libs], FRAMEWORKS=frameworks)
|
||||
lenvCython.Program('models/driving_pyx.so', 'models/driving_pyx.pyx', LIBS=[driving_lib, commonmodel_lib, *cython_libs], FRAMEWORKS=frameworks)
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import numpy as np
|
||||
@@ -8,25 +7,21 @@ from typing import Dict, Optional
|
||||
from setproctitle import setproctitle
|
||||
from cereal.messaging import PubMaster, SubMaster
|
||||
from cereal.visionipc import VisionIpcClient, VisionStreamType, VisionBuf
|
||||
from openpilot.system.hardware import PC, TICI
|
||||
from openpilot.system.swaglog import cloudlog
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.filter_simple import FirstOrderFilter
|
||||
from openpilot.common.realtime import config_realtime_process
|
||||
from openpilot.common.transformations.model import get_warp_matrix
|
||||
from openpilot.selfdrive.modeld.models.commonmodel_pyx import ModelFrame, CLContext, Runtime
|
||||
from openpilot.selfdrive.modeld.runners import ModelRunner, Runtime
|
||||
from openpilot.selfdrive.modeld.models.commonmodel_pyx import ModelFrame, CLContext
|
||||
from openpilot.selfdrive.modeld.models.driving_pyx import (
|
||||
PublishState, create_model_msg, create_pose_msg,
|
||||
FEATURE_LEN, HISTORY_BUFFER_LEN, DESIRE_LEN, TRAFFIC_CONVENTION_LEN, NAV_FEATURE_LEN, NAV_INSTRUCTION_LEN,
|
||||
OUTPUT_SIZE, NET_OUTPUT_SIZE, MODEL_FREQ)
|
||||
|
||||
USE_THNEED = int(os.getenv('USE_THNEED', str(int(TICI))))
|
||||
if USE_THNEED:
|
||||
from selfdrive.modeld.runners.thneedmodel_pyx import ThneedModel as ModelRunner
|
||||
else:
|
||||
from selfdrive.modeld.runners.onnxmodel_pyx import ONNXModel as ModelRunner
|
||||
|
||||
MODEL_PATH = str(Path(__file__).parent / f"models/supercombo.{'thneed' if USE_THNEED else 'onnx'}")
|
||||
MODEL_PATHS = {
|
||||
ModelRunner.THNEED: Path(__file__).parent / 'models/supercombo.thneed',
|
||||
ModelRunner.ONNX: Path(__file__).parent / 'models/supercombo.onnx'}
|
||||
|
||||
class FrameMeta:
|
||||
frame_id: int = 0
|
||||
@@ -58,7 +53,7 @@ class ModelState:
|
||||
'feature_buffer': np.zeros(HISTORY_BUFFER_LEN * FEATURE_LEN, dtype=np.float32),
|
||||
}
|
||||
|
||||
self.model = ModelRunner(MODEL_PATH, self.output, Runtime.GPU, False, context)
|
||||
self.model = ModelRunner(MODEL_PATHS, self.output, Runtime.GPU, False, context)
|
||||
self.model.addInput("input_imgs", None)
|
||||
self.model.addInput("big_input_imgs", None)
|
||||
for k,v in self.inputs.items():
|
||||
@@ -94,8 +89,7 @@ class ModelState:
|
||||
def main():
|
||||
cloudlog.bind(daemon="selfdrive.modeld.modeld")
|
||||
setproctitle("selfdrive.modeld.modeld")
|
||||
if not PC:
|
||||
config_realtime_process(7, 54)
|
||||
config_realtime_process(7, 54)
|
||||
|
||||
cl_context = CLContext()
|
||||
model = ModelState(cl_context)
|
||||
|
||||
@@ -12,12 +12,9 @@ cdef extern from "common/clutil.h":
|
||||
cl_context cl_create_context(cl_device_id)
|
||||
|
||||
cdef extern from "selfdrive/modeld/models/commonmodel.h":
|
||||
float sigmoid(float)
|
||||
|
||||
cppclass ModelFrame:
|
||||
int buf_size
|
||||
ModelFrame(cl_device_id, cl_context)
|
||||
float * prepare(cl_mem, int, int, int, int, mat3, cl_mem*)
|
||||
|
||||
cdef extern from "selfdrive/modeld/runners/runmodel.h":
|
||||
cdef int USE_CPU_RUNTIME
|
||||
cdef int USE_GPU_RUNTIME
|
||||
cdef int USE_DSP_RUNTIME
|
||||
|
||||
@@ -8,13 +8,10 @@ from libc.string cimport memcpy
|
||||
from cereal.visionipc.visionipc cimport cl_mem
|
||||
from cereal.visionipc.visionipc_pyx cimport VisionBuf, CLContext as BaseCLContext
|
||||
from .commonmodel cimport CL_DEVICE_TYPE_DEFAULT, cl_get_device_id, cl_create_context
|
||||
from .commonmodel cimport USE_CPU_RUNTIME, USE_GPU_RUNTIME, USE_DSP_RUNTIME
|
||||
from .commonmodel cimport mat3, ModelFrame as cppModelFrame
|
||||
from .commonmodel cimport mat3, sigmoid as cppSigmoid, ModelFrame as cppModelFrame
|
||||
|
||||
class Runtime:
|
||||
CPU = USE_CPU_RUNTIME
|
||||
GPU = USE_GPU_RUNTIME
|
||||
DSP = USE_DSP_RUNTIME
|
||||
def sigmoid(x):
|
||||
return cppSigmoid(x)
|
||||
|
||||
cdef class CLContext(BaseCLContext):
|
||||
def __cinit__(self):
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
from libcpp cimport bool
|
||||
from libc.stdint cimport uint32_t, uint64_t
|
||||
|
||||
from .commonmodel cimport mat3
|
||||
|
||||
cdef extern from "cereal/messaging/messaging.h":
|
||||
cdef cppclass MessageBuilder:
|
||||
size_t getSerializedSize()
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import os
|
||||
from openpilot.system.hardware import TICI
|
||||
from openpilot.selfdrive.modeld.runners.runmodel_pyx import RunModel, Runtime
|
||||
assert Runtime
|
||||
|
||||
USE_THNEED = int(os.getenv('USE_THNEED', str(int(TICI))))
|
||||
USE_SNPE = int(os.getenv('USE_SNPE', str(int(TICI))))
|
||||
|
||||
class ModelRunner(RunModel):
|
||||
THNEED = 'THNEED'
|
||||
SNPE = 'SNPE'
|
||||
ONNX = 'ONNX'
|
||||
|
||||
def __new__(cls, paths, *args, **kwargs):
|
||||
if ModelRunner.THNEED in paths and USE_THNEED:
|
||||
from openpilot.selfdrive.modeld.runners.thneedmodel_pyx import ThneedModel as Runner
|
||||
runner_type = ModelRunner.THNEED
|
||||
elif ModelRunner.SNPE in paths and USE_SNPE:
|
||||
from openpilot.selfdrive.modeld.runners.snpemodel_pyx import SNPEModel as Runner
|
||||
runner_type = ModelRunner.SNPE
|
||||
elif ModelRunner.ONNX in paths:
|
||||
from openpilot.selfdrive.modeld.runners.onnxmodel_pyx import ONNXModel as Runner
|
||||
runner_type = ModelRunner.ONNX
|
||||
else:
|
||||
raise Exception("Couldn't select a model runner, make sure to pass at least one valid model path")
|
||||
|
||||
return Runner(str(paths[runner_type]), *args, **kwargs)
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
from libcpp.string cimport string
|
||||
|
||||
cdef extern from "selfdrive/modeld/runners/runmodel.h":
|
||||
cdef int USE_CPU_RUNTIME
|
||||
cdef int USE_GPU_RUNTIME
|
||||
cdef int USE_DSP_RUNTIME
|
||||
|
||||
cdef cppclass RunModel:
|
||||
void addInput(string, float*, int)
|
||||
void setInputBuffer(string, float*, int)
|
||||
|
||||
@@ -4,8 +4,14 @@
|
||||
from libcpp.string cimport string
|
||||
from libc.string cimport memcpy
|
||||
|
||||
from .runmodel cimport USE_CPU_RUNTIME, USE_GPU_RUNTIME, USE_DSP_RUNTIME
|
||||
from selfdrive.modeld.models.commonmodel_pyx cimport CLMem
|
||||
|
||||
class Runtime:
|
||||
CPU = USE_CPU_RUNTIME
|
||||
GPU = USE_GPU_RUNTIME
|
||||
DSP = USE_DSP_RUNTIME
|
||||
|
||||
cdef class RunModel:
|
||||
def __dealloc__(self):
|
||||
del self.model
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# distutils: language = c++
|
||||
# cython: c_string_encoding=ascii
|
||||
|
||||
import os
|
||||
from libcpp cimport bool
|
||||
from libcpp.string cimport string
|
||||
|
||||
@@ -9,6 +10,8 @@ from selfdrive.modeld.models.commonmodel_pyx cimport CLContext
|
||||
from selfdrive.modeld.runners.runmodel_pyx cimport RunModel
|
||||
from selfdrive.modeld.runners.runmodel cimport RunModel as cppRunModel
|
||||
|
||||
os.environ['ADSP_LIBRARY_PATH'] = "/data/pythonpath/third_party/snpe/dsp/"
|
||||
|
||||
cdef class SNPEModel(RunModel):
|
||||
def __cinit__(self, string path, float[:] output, int runtime, bool use_tf8, CLContext context):
|
||||
self.model = <cppRunModel *> new cppSNPEModel(path, &output[0], len(output), runtime, use_tf8, context.context)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import os
|
||||
import time
|
||||
import tempfile
|
||||
from typing import List, Union
|
||||
|
||||
from unittest import mock
|
||||
from functools import wraps
|
||||
@@ -11,6 +12,7 @@ from openpilot.selfdrive.manager.process_config import managed_processes
|
||||
from openpilot.system.hardware import PC
|
||||
from openpilot.system.version import training_version, terms_version
|
||||
|
||||
SKIP_ENV_VAR = "SKIP_LONG_TESTS"
|
||||
|
||||
def set_params_enabled():
|
||||
os.environ['PASSIVE'] = "0"
|
||||
@@ -72,17 +74,44 @@ def with_processes(processes, init_time=0, ignore_stopped=None):
|
||||
return wrapper
|
||||
|
||||
|
||||
def temporary_mock_dir(mock_path):
|
||||
def temporary_mock_dir(mock_paths_in: Union[List[str], str], kwarg: Union[str, None] = None, generator = tempfile.TemporaryDirectory):
|
||||
"""
|
||||
mock_paths_in: string or string list representing the full path of the variable you want to mock.
|
||||
kwarg: str or None representing the kwarg that gets passed into the test function, in case the test needs access to the temporary directory.
|
||||
generator: a context to use to generate the temporary directory
|
||||
"""
|
||||
def wrapper(func):
|
||||
@wraps(func)
|
||||
def wrap(*args, **kwargs):
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
cache_dir_patch = mock.patch(mock_path, temp_dir)
|
||||
cache_dir_patch.start()
|
||||
func(*args, **kwargs, temp_dir=temp_dir)
|
||||
cache_dir_patch.stop()
|
||||
mock_paths = mock_paths_in if isinstance(mock_paths_in, list) else [mock_paths_in]
|
||||
with generator() as temp_dir:
|
||||
mocks = []
|
||||
for mock_path in mock_paths:
|
||||
mocks.append(mock.patch(mock_path, str(temp_dir)))
|
||||
[mock.start() for mock in mocks]
|
||||
try:
|
||||
if kwarg is not None:
|
||||
kwargs[kwarg] = temp_dir
|
||||
func(*args, **kwargs)
|
||||
finally:
|
||||
[mock.stop() for mock in mocks]
|
||||
|
||||
return wrap
|
||||
return wrapper
|
||||
|
||||
def string_context(context):
|
||||
class StringContext:
|
||||
def __enter__(self):
|
||||
return context
|
||||
|
||||
def __exit__(self, *args):
|
||||
pass
|
||||
|
||||
return StringContext
|
||||
|
||||
temporary_dir = temporary_mock_dir([], "temp_dir")
|
||||
temporary_cache_dir = temporary_mock_dir("openpilot.tools.lib.url_file.CACHE_DIR")
|
||||
temporary_swaglog_dir = temporary_mock_dir("openpilot.system.swaglog.SWAGLOG_DIR")
|
||||
temporary_swaglog_dir = temporary_mock_dir("openpilot.system.swaglog.SWAGLOG_DIR", "temp_dir")
|
||||
temporary_laikad_downloads_dir = temporary_mock_dir("openpilot.selfdrive.locationd.laikad.DOWNLOADS_CACHE_FOLDER")
|
||||
temporary_swaglog_ipc = temporary_mock_dir(["openpilot.system.swaglog.SWAGLOG_IPC", "system.logmessaged.SWAGLOG_IPC"],
|
||||
generator=string_context("/tmp/test_swaglog_ipc"))
|
||||
@@ -17,12 +17,12 @@ from cereal import car
|
||||
from cereal.services import service_list
|
||||
from cereal.visionipc import VisionIpcServer, get_endpoint_name as vipc_get_endpoint_name
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.prefix import OpenpilotPrefix
|
||||
from openpilot.common.timeout import Timeout
|
||||
from openpilot.common.realtime import DT_CTRL
|
||||
from panda.python import ALTERNATIVE_EXPERIENCE
|
||||
from openpilot.selfdrive.car.car_helpers import get_car, interfaces
|
||||
from openpilot.selfdrive.manager.process_config import managed_processes
|
||||
from openpilot.selfdrive.test.process_replay.helpers import OpenpilotPrefix, DummySocket
|
||||
from openpilot.selfdrive.test.process_replay.vision_meta import meta_from_camera_state, available_streams
|
||||
from openpilot.selfdrive.test.process_replay.migration import migrate_all
|
||||
from openpilot.selfdrive.test.process_replay.capture import ProcessOutputCapture
|
||||
@@ -33,6 +33,18 @@ NUMPY_TOLERANCE = 1e-7
|
||||
PROC_REPLAY_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
FAKEDATA = os.path.join(PROC_REPLAY_DIR, "fakedata/")
|
||||
|
||||
class DummySocket:
|
||||
def __init__(self):
|
||||
self.data: List[bytes] = []
|
||||
|
||||
def receive(self, non_blocking: bool = False) -> Optional[bytes]:
|
||||
if non_blocking:
|
||||
return None
|
||||
|
||||
return self.data.pop()
|
||||
|
||||
def send(self, data: bytes):
|
||||
self.data.append(data)
|
||||
|
||||
class LauncherWithCapture:
|
||||
def __init__(self, capture: ProcessOutputCapture, launcher: Callable):
|
||||
|
||||
@@ -6,7 +6,7 @@ import random
|
||||
import traceback
|
||||
from tqdm import tqdm
|
||||
|
||||
from openpilot.selfdrive.test.process_replay.helpers import OpenpilotPrefix
|
||||
from openpilot.common.prefix import OpenpilotPrefix
|
||||
from openpilot.selfdrive.test.process_replay.regen import regen_and_save
|
||||
from openpilot.selfdrive.test.process_replay.test_processes import FAKEDATA, source_segments as segments
|
||||
from openpilot.tools.lib.route import SegmentName
|
||||
|
||||
Regular → Executable
@@ -25,12 +25,9 @@ def pm_patch(name, value, constant=False):
|
||||
|
||||
|
||||
@patch("time.monotonic", new=mock_time_monotonic)
|
||||
@patch("openpilot.selfdrive.thermald.power_monitoring.put_nonblocking", new=lambda x, y: Params().put(x, y))
|
||||
class TestPowerMonitoring(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.params = Params()
|
||||
self.params.remove("CarBatteryCapacity")
|
||||
self.params.remove("DisablePowerDown")
|
||||
|
||||
# Test to see that it doesn't do anything when pandaState is None
|
||||
def test_pandaState_present(self):
|
||||
|
||||
@@ -14,21 +14,21 @@ MapPanel::MapPanel(const QMapboxGLSettings &mapboxSettings, QWidget *parent) : Q
|
||||
|
||||
auto map = new MapWindow(mapboxSettings);
|
||||
QObject::connect(uiState(), &UIState::offroadTransition, map, &MapWindow::offroadTransition);
|
||||
QObject::connect(device(), &Device::interactiveTimeout, [=]() {
|
||||
QObject::connect(device(), &Device::interactiveTimeout, this, [=]() {
|
||||
content_stack->setCurrentIndex(0);
|
||||
});
|
||||
QObject::connect(map, &MapWindow::requestVisible, [=](bool visible) {
|
||||
QObject::connect(map, &MapWindow::requestVisible, this, [=](bool visible) {
|
||||
// when we show the map for a new route, signal HomeWindow to hide the sidebar
|
||||
if (visible) { emit mapPanelRequested(); }
|
||||
setVisible(visible);
|
||||
});
|
||||
QObject::connect(map, &MapWindow::requestSettings, [=](bool settings) {
|
||||
QObject::connect(map, &MapWindow::requestSettings, this, [=](bool settings) {
|
||||
content_stack->setCurrentIndex(settings ? 1 : 0);
|
||||
});
|
||||
content_stack->addWidget(map);
|
||||
|
||||
auto settings = new MapSettings(true, parent);
|
||||
QObject::connect(settings, &MapSettings::closeSettings, [=]() {
|
||||
QObject::connect(settings, &MapSettings::closeSettings, this, [=]() {
|
||||
content_stack->setCurrentIndex(0);
|
||||
});
|
||||
content_stack->addWidget(settings);
|
||||
|
||||
@@ -41,6 +41,8 @@ const char frame_fragment_shader[] =
|
||||
"out vec4 colorOut;\n"
|
||||
"void main() {\n"
|
||||
" colorOut = texture(uTexture, vTexCoord);\n"
|
||||
// gamma to improve worst case visibility when dark
|
||||
" colorOut.rgb = pow(colorOut.rgb, vec3(1.0/1.28));\n"
|
||||
"}\n";
|
||||
#else
|
||||
const char frame_fragment_shader[] =
|
||||
|
||||
@@ -15,12 +15,13 @@
|
||||
Sound::Sound(QObject *parent) : sm({"controlsState", "microphone"}) {
|
||||
qInfo() << "default audio device: " << QAudioDeviceInfo::defaultOutputDevice().deviceName();
|
||||
|
||||
for (auto &[alert, fn, loops] : sound_list) {
|
||||
for (auto &[alert, fn, loops, volume] : sound_list) {
|
||||
QSoundEffect *s = new QSoundEffect(this);
|
||||
QObject::connect(s, &QSoundEffect::statusChanged, [=]() {
|
||||
assert(s->status() != QSoundEffect::Error);
|
||||
});
|
||||
s->setSource(QUrl::fromLocalFile("../../assets/sounds/" + fn));
|
||||
s->setVolume(volume);
|
||||
sounds[alert] = {s, loops};
|
||||
}
|
||||
|
||||
|
||||
@@ -9,18 +9,21 @@
|
||||
#include "system/hardware/hw.h"
|
||||
#include "selfdrive/ui/ui.h"
|
||||
|
||||
const std::tuple<AudibleAlert, QString, int> sound_list[] = {
|
||||
|
||||
const float MAX_VOLUME = 1.0;
|
||||
|
||||
const std::tuple<AudibleAlert, QString, int, float> sound_list[] = {
|
||||
// AudibleAlert, file name, loop count
|
||||
{AudibleAlert::ENGAGE, "engage.wav", 0},
|
||||
{AudibleAlert::DISENGAGE, "disengage.wav", 0},
|
||||
{AudibleAlert::REFUSE, "refuse.wav", 0},
|
||||
{AudibleAlert::ENGAGE, "engage.wav", 0, MAX_VOLUME},
|
||||
{AudibleAlert::DISENGAGE, "disengage.wav", 0, MAX_VOLUME},
|
||||
{AudibleAlert::REFUSE, "refuse.wav", 0, MAX_VOLUME},
|
||||
|
||||
{AudibleAlert::PROMPT, "prompt.wav", 0},
|
||||
{AudibleAlert::PROMPT_REPEAT, "prompt.wav", QSoundEffect::Infinite},
|
||||
{AudibleAlert::PROMPT_DISTRACTED, "prompt_distracted.wav", QSoundEffect::Infinite},
|
||||
{AudibleAlert::PROMPT, "prompt.wav", 0, MAX_VOLUME},
|
||||
{AudibleAlert::PROMPT_REPEAT, "prompt.wav", QSoundEffect::Infinite, MAX_VOLUME},
|
||||
{AudibleAlert::PROMPT_DISTRACTED, "prompt_distracted.wav", QSoundEffect::Infinite, MAX_VOLUME},
|
||||
|
||||
{AudibleAlert::WARNING_SOFT, "warning_soft.wav", QSoundEffect::Infinite},
|
||||
{AudibleAlert::WARNING_IMMEDIATE, "warning_immediate.wav", QSoundEffect::Infinite},
|
||||
{AudibleAlert::WARNING_SOFT, "warning_soft.wav", QSoundEffect::Infinite, MAX_VOLUME},
|
||||
{AudibleAlert::WARNING_IMMEDIATE, "warning_immediate.wav", QSoundEffect::Infinite, MAX_VOLUME},
|
||||
};
|
||||
|
||||
class Sound : public QObject {
|
||||
|
||||
@@ -31,7 +31,7 @@ void controls_thread(int loop_cnt) {
|
||||
|
||||
const int DT_CTRL = 10; // ms
|
||||
for (int i = 0; i < loop_cnt; ++i) {
|
||||
for (auto &[alert, fn, loops] : sound_list) {
|
||||
for (auto &[alert, fn, loops, volume] : sound_list) {
|
||||
printf("testing %s\n", qPrintable(fn));
|
||||
for (int j = 0; j < 1000 / DT_CTRL; ++j) {
|
||||
MessageBuilder msg;
|
||||
|
||||
@@ -11,8 +11,8 @@ from openpilot.selfdrive.manager.process_config import managed_processes
|
||||
from openpilot.system.hardware import TICI
|
||||
|
||||
TEST_TIMESPAN = 30
|
||||
LAG_FRAME_TOLERANCE = {log.FrameData.ImageSensor.ar0231: 0.5, # ARs use synced pulses for frame starts
|
||||
log.FrameData.ImageSensor.ox03c10: 1.0} # OXs react to out-of-sync at next frame
|
||||
LAG_FRAME_TOLERANCE = {log.FrameData.ImageSensor.ar0231: 0.5, # ARs use synced pulses for frame starts
|
||||
log.FrameData.ImageSensor.ox03c10: 1.1} # OXs react to out-of-sync at next frame
|
||||
FRAME_DELTA_TOLERANCE = {log.FrameData.ImageSensor.ar0231: 1.0,
|
||||
log.FrameData.ImageSensor.ox03c10: 1.0}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
import time
|
||||
from smbus2 import SMBus
|
||||
from collections import namedtuple
|
||||
|
||||
Regular → Executable
@@ -135,7 +135,7 @@ int FfmpegEncoder::encode_frame(VisionBuf* buf, VisionIpcBufExtra *extra) {
|
||||
}
|
||||
|
||||
if (env_debug_encoder) {
|
||||
printf("%20s got %8d bytes flags %8x idx %4d id %8d\n", encoder_info.filename, pkt.size, pkt.flags, counter, extra->frame_id);
|
||||
printf("%20s got %8d bytes flags %8x idx %4d id %8d\n", encoder_info.publish_name, pkt.size, pkt.flags, counter, extra->frame_id);
|
||||
}
|
||||
|
||||
publisher_publish(this, segment_num, counter, *extra,
|
||||
|
||||
@@ -75,7 +75,7 @@ static void request_buffers(int fd, v4l2_buf_type buf_type, unsigned int count)
|
||||
}
|
||||
|
||||
void V4LEncoder::dequeue_handler(V4LEncoder *e) {
|
||||
std::string dequeue_thread_name = "dq-"+std::string(e->encoder_info.filename);
|
||||
std::string dequeue_thread_name = "dq-"+std::string(e->encoder_info.publish_name);
|
||||
util::set_thread_name(dequeue_thread_name.c_str());
|
||||
|
||||
e->segment_num++;
|
||||
@@ -105,7 +105,7 @@ void V4LEncoder::dequeue_handler(V4LEncoder *e) {
|
||||
}
|
||||
|
||||
if (env_debug_encoder >= 2) {
|
||||
printf("%20s poll %x at %.2f ms\n", e->encoder_info.filename, pfd.revents, millis_since_boot());
|
||||
printf("%20s poll %x at %.2f ms\n", e->encoder_info.publish_name, pfd.revents, millis_since_boot());
|
||||
}
|
||||
|
||||
int frame_id = -1;
|
||||
@@ -133,7 +133,7 @@ void V4LEncoder::dequeue_handler(V4LEncoder *e) {
|
||||
|
||||
if (env_debug_encoder) {
|
||||
printf("%20s got(%d) %6d bytes flags %8x idx %3d/%4d id %8d ts %ld lat %.2f ms (%lu frames free)\n",
|
||||
e->encoder_info.filename, index, bytesused, flags, e->segment_num, idx, frame_id, ts, millis_since_boot()-(ts/1000.), e->free_buf_in.size());
|
||||
e->encoder_info.publish_name, index, bytesused, flags, e->segment_num, idx, frame_id, ts, millis_since_boot()-(ts/1000.), e->free_buf_in.size());
|
||||
}
|
||||
|
||||
// requeue the buffer
|
||||
|
||||
@@ -116,6 +116,7 @@ int handle_encoder_msg(LoggerdState *s, Message *msg, std::string &name, struct
|
||||
}
|
||||
// if we aren't actually recording, don't create the writer
|
||||
if (encoder_info.record) {
|
||||
assert(encoder_info.filename != NULL);
|
||||
re.writer.reset(new VideoWriter(s->segment_path,
|
||||
encoder_info.filename, idx.getType() != cereal::EncodeIndex::Type::FULL_H_E_V_C,
|
||||
encoder_info.frame_width, encoder_info.frame_height, encoder_info.fps, idx.getType()));
|
||||
|
||||
Regular → Executable
@@ -5,6 +5,7 @@ from typing import NoReturn
|
||||
import cereal.messaging as messaging
|
||||
from openpilot.common.logging_extra import SwagLogFileFormatter
|
||||
from openpilot.system.swaglog import get_file_handler
|
||||
from system.swaglog import SWAGLOG_IPC
|
||||
|
||||
|
||||
def main() -> NoReturn:
|
||||
@@ -14,7 +15,7 @@ def main() -> NoReturn:
|
||||
|
||||
ctx = zmq.Context.instance()
|
||||
sock = ctx.socket(zmq.PULL)
|
||||
sock.bind("ipc:///tmp/logmessage")
|
||||
sock.bind(f"ipc://{SWAGLOG_IPC}")
|
||||
|
||||
# and we publish them
|
||||
log_message_sock = messaging.pub_sock('logMessage')
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
import os
|
||||
import sys
|
||||
from dataclasses import dataclass, fields
|
||||
from subprocess import check_output, CalledProcessError
|
||||
from time import sleep
|
||||
from typing import NoReturn
|
||||
|
||||
DEBUG = int(os.environ.get("DEBUG", "0"))
|
||||
|
||||
@dataclass
|
||||
class GnssClockNmeaPort:
|
||||
# flags bit mask:
|
||||
# 0x01 = leap_seconds valid
|
||||
# 0x02 = time_uncertainty_ns valid
|
||||
# 0x04 = full_bias_ns valid
|
||||
# 0x08 = bias_ns valid
|
||||
# 0x10 = bias_uncertainty_ns valid
|
||||
# 0x20 = drift_nsps valid
|
||||
# 0x40 = drift_uncertainty_nsps valid
|
||||
flags: int
|
||||
leap_seconds: int
|
||||
time_ns: int
|
||||
time_uncertainty_ns: int # 1-sigma
|
||||
full_bias_ns: int
|
||||
bias_ns: float
|
||||
bias_uncertainty_ns: float # 1-sigma
|
||||
drift_nsps: float
|
||||
drift_uncertainty_nsps: float # 1-sigma
|
||||
|
||||
def __post_init__(self):
|
||||
for field in fields(self):
|
||||
val = getattr(self, field.name)
|
||||
setattr(self, field.name, field.type(val) if val else None)
|
||||
|
||||
@dataclass
|
||||
class GnssMeasNmeaPort:
|
||||
messageCount: int
|
||||
messageNum: int
|
||||
svCount: int
|
||||
# constellation enum:
|
||||
# 1 = GPS
|
||||
# 2 = SBAS
|
||||
# 3 = GLONASS
|
||||
# 4 = QZSS
|
||||
# 5 = BEIDOU
|
||||
# 6 = GALILEO
|
||||
constellation: int
|
||||
svId: int
|
||||
flags: int # always zero
|
||||
time_offset_ns: int
|
||||
# state bit mask:
|
||||
# 0x0001 = CODE LOCK
|
||||
# 0x0002 = BIT SYNC
|
||||
# 0x0004 = SUBFRAME SYNC
|
||||
# 0x0008 = TIME OF WEEK DECODED
|
||||
# 0x0010 = MSEC AMBIGUOUS
|
||||
# 0x0020 = SYMBOL SYNC
|
||||
# 0x0040 = GLONASS STRING SYNC
|
||||
# 0x0080 = GLONASS TIME OF DAY DECODED
|
||||
# 0x0100 = BEIDOU D2 BIT SYNC
|
||||
# 0x0200 = BEIDOU D2 SUBFRAME SYNC
|
||||
# 0x0400 = GALILEO E1BC CODE LOCK
|
||||
# 0x0800 = GALILEO E1C 2ND CODE LOCK
|
||||
# 0x1000 = GALILEO E1B PAGE SYNC
|
||||
# 0x2000 = GALILEO E1B PAGE SYNC
|
||||
state: int
|
||||
time_of_week_ns: int
|
||||
time_of_week_uncertainty_ns: int # 1-sigma
|
||||
carrier_to_noise_ratio: float
|
||||
pseudorange_rate: float
|
||||
pseudorange_rate_uncertainty: float # 1-sigma
|
||||
|
||||
def __post_init__(self):
|
||||
for field in fields(self):
|
||||
val = getattr(self, field.name)
|
||||
setattr(self, field.name, field.type(val) if val else None)
|
||||
|
||||
def nmea_checksum_ok(s):
|
||||
checksum = 0
|
||||
for i, c in enumerate(s[1:]):
|
||||
if c == "*":
|
||||
if i != len(s) - 4: # should be 3rd to last character
|
||||
print("ERROR: NMEA string does not have checksum delimiter in correct location:", s)
|
||||
return False
|
||||
break
|
||||
checksum ^= ord(c)
|
||||
else:
|
||||
print("ERROR: NMEA string does not have checksum delimiter:", s)
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def process_nmea_port_messages(device:str="/dev/ttyUSB1") -> NoReturn:
|
||||
while True:
|
||||
try:
|
||||
with open(device, "r") as nmeaport:
|
||||
for line in nmeaport:
|
||||
line = line.strip()
|
||||
if DEBUG:
|
||||
print(line)
|
||||
if not line.startswith("$"): # all NMEA messages start with $
|
||||
continue
|
||||
if not nmea_checksum_ok(line):
|
||||
continue
|
||||
|
||||
fields = line.split(",")
|
||||
match fields[0]:
|
||||
case "$GNCLK":
|
||||
# fields at end are reserved (not used)
|
||||
gnss_clock = GnssClockNmeaPort(*fields[1:10]) # type: ignore[arg-type]
|
||||
print(gnss_clock)
|
||||
case "$GNMEAS":
|
||||
# fields at end are reserved (not used)
|
||||
gnss_meas = GnssMeasNmeaPort(*fields[1:14]) # type: ignore[arg-type]
|
||||
print(gnss_meas)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
sleep(1)
|
||||
|
||||
def main() -> NoReturn:
|
||||
from openpilot.common.gpio import gpio_init, gpio_set
|
||||
from openpilot.system.hardware.tici.pins import GPIO
|
||||
from openpilot.system.sensord.rawgps.rawgpsd import at_cmd
|
||||
|
||||
try:
|
||||
check_output(["pidof", "rawgpsd"])
|
||||
print("rawgpsd is running, please kill openpilot before running this script! (aborted)")
|
||||
sys.exit(1)
|
||||
except CalledProcessError as e:
|
||||
if e.returncode != 1: # 1 == no process found (boardd not running)
|
||||
raise e
|
||||
|
||||
print("power up antenna ...")
|
||||
gpio_init(GPIO.GNSS_PWR_EN, True)
|
||||
gpio_set(GPIO.GNSS_PWR_EN, True)
|
||||
|
||||
if b"+QGPS: 0" not in (at_cmd("AT+QGPS?") or b""):
|
||||
print("stop location tracking ...")
|
||||
at_cmd("AT+QGPSEND")
|
||||
|
||||
if b'+QGPSCFG: "outport",usbnmea' not in (at_cmd('AT+QGPSCFG="outport"') or b""):
|
||||
print("configure outport ...")
|
||||
at_cmd('AT+QGPSCFG="outport","usbnmea"') # usbnmea = /dev/ttyUSB1
|
||||
|
||||
if b'+QGPSCFG: "gnssrawdata",3,0' not in (at_cmd('AT+QGPSCFG="gnssrawdata"') or b""):
|
||||
print("configure gnssrawdata ...")
|
||||
# AT+QGPSCFG="gnssrawdata",<constellation-mask>,<port>'
|
||||
# <constellation-mask> values:
|
||||
# 0x01 = GPS
|
||||
# 0x02 = GLONASS
|
||||
# 0x04 = BEIDOU
|
||||
# 0x08 = GALILEO
|
||||
# 0x10 = QZSS
|
||||
# <port> values:
|
||||
# 0 = NMEA port
|
||||
# 1 = AT port
|
||||
at_cmd('AT+QGPSCFG="gnssrawdata",3,0') # enable all constellations, output data to NMEA port
|
||||
print("rebooting ...")
|
||||
at_cmd('AT+CFUN=1,1')
|
||||
print("re-run this script when it is back up")
|
||||
sys.exit(2)
|
||||
|
||||
print("starting location tracking ...")
|
||||
at_cmd("AT+QGPS=1")
|
||||
|
||||
process_nmea_port_messages()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -9,6 +9,7 @@ import cereal.messaging as messaging
|
||||
from cereal import log
|
||||
from cereal.services import service_list
|
||||
from openpilot.common.gpio import get_irqs_for_action
|
||||
from openpilot.common.timeout import Timeout
|
||||
from openpilot.system.hardware import TICI
|
||||
from openpilot.selfdrive.manager.process_config import managed_processes
|
||||
|
||||
@@ -73,15 +74,24 @@ def get_irq_count(irq: int):
|
||||
def read_sensor_events(duration_sec):
|
||||
sensor_types = ['accelerometer', 'gyroscope', 'magnetometer', 'accelerometer2',
|
||||
'gyroscope2', 'temperatureSensor', 'temperatureSensor2']
|
||||
esocks = {}
|
||||
socks = {}
|
||||
poller = messaging.Poller()
|
||||
events = defaultdict(list)
|
||||
for stype in sensor_types:
|
||||
esocks[stype] = messaging.sub_sock(stype, timeout=0.1)
|
||||
socks[stype] = messaging.sub_sock(stype, poller=poller, timeout=100)
|
||||
|
||||
start_time_sec = time.monotonic()
|
||||
while time.monotonic() - start_time_sec < duration_sec:
|
||||
for esock in esocks:
|
||||
events[esock] += messaging.drain_sock(esocks[esock])
|
||||
# wait for sensors to come up
|
||||
with Timeout(60, "sensors didn't come up"):
|
||||
while len(poller.poll(250)) == 0:
|
||||
pass
|
||||
time.sleep(1)
|
||||
for s in socks.values():
|
||||
messaging.drain_sock_raw(s)
|
||||
|
||||
st = time.monotonic()
|
||||
while time.monotonic() - st < duration_sec:
|
||||
for s in socks:
|
||||
events[s] += messaging.drain_sock(socks[s])
|
||||
time.sleep(0.1)
|
||||
|
||||
assert sum(map(len, events.values())) != 0, "No sensor events collected!"
|
||||
@@ -101,8 +111,7 @@ class TestSensord(unittest.TestCase):
|
||||
os.system("pkill -f ./_sensord")
|
||||
try:
|
||||
managed_processes["sensord"].start()
|
||||
time.sleep(3)
|
||||
cls.sample_secs = 10
|
||||
cls.sample_secs = int(os.getenv("SAMPLE_SECS", "10"))
|
||||
cls.events = read_sensor_events(cls.sample_secs)
|
||||
|
||||
# determine sensord's irq
|
||||
|
||||
+3
-1
@@ -15,6 +15,8 @@ if PC:
|
||||
else:
|
||||
SWAGLOG_DIR = "/data/log/"
|
||||
|
||||
SWAGLOG_IPC = "/tmp/logmessage"
|
||||
|
||||
def get_file_handler():
|
||||
Path(SWAGLOG_DIR).mkdir(parents=True, exist_ok=True)
|
||||
base_filename = os.path.join(SWAGLOG_DIR, "swaglog")
|
||||
@@ -89,7 +91,7 @@ class UnixDomainSocketHandler(logging.Handler):
|
||||
self.zctx = zmq.Context()
|
||||
self.sock = self.zctx.socket(zmq.PUSH)
|
||||
self.sock.setsockopt(zmq.LINGER, 10)
|
||||
self.sock.connect("ipc:///tmp/logmessage")
|
||||
self.sock.connect(f"ipc://{SWAGLOG_IPC}")
|
||||
self.pid = os.getpid()
|
||||
|
||||
def emit(self, record):
|
||||
|
||||
@@ -7,7 +7,7 @@ import unittest
|
||||
import cereal.messaging as messaging
|
||||
from openpilot.selfdrive.manager.process_config import managed_processes
|
||||
from openpilot.system.swaglog import cloudlog, ipchandler
|
||||
from selfdrive.test.helpers import temporary_swaglog_dir
|
||||
from openpilot.selfdrive.test.helpers import temporary_swaglog_dir, temporary_swaglog_ipc
|
||||
|
||||
|
||||
class TestLogmessaged(unittest.TestCase):
|
||||
@@ -35,6 +35,7 @@ class TestLogmessaged(unittest.TestCase):
|
||||
return list(glob.glob(os.path.join(self.temp_dir, "swaglog.*")))
|
||||
|
||||
@temporary_swaglog_dir
|
||||
@temporary_swaglog_ipc
|
||||
def test_simple_log(self, temp_dir):
|
||||
self._setup(temp_dir)
|
||||
msgs = [f"abc {i}" for i in range(10)]
|
||||
@@ -46,6 +47,7 @@ class TestLogmessaged(unittest.TestCase):
|
||||
assert len(self._get_log_files()) >= 1
|
||||
|
||||
@temporary_swaglog_dir
|
||||
@temporary_swaglog_ipc
|
||||
def test_big_log(self, temp_dir):
|
||||
self._setup(temp_dir)
|
||||
n = 10
|
||||
|
||||
+5
-2
@@ -11,6 +11,9 @@ from timezonefinder import TimezoneFinder
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.system.hardware import AGNOS
|
||||
from openpilot.system.swaglog import cloudlog
|
||||
from openpilot.system.version import get_version
|
||||
|
||||
REQUEST_HEADERS = {'User-Agent': "openpilot-" + get_version()}
|
||||
|
||||
|
||||
def set_timezone(valid_timezones, timezone):
|
||||
@@ -18,7 +21,7 @@ def set_timezone(valid_timezones, timezone):
|
||||
cloudlog.error(f"Timezone not supported {timezone}")
|
||||
return
|
||||
|
||||
cloudlog.debug(f"Setting timezone to {timezone}")
|
||||
cloudlog.info(f"Setting timezone to {timezone}")
|
||||
try:
|
||||
if AGNOS:
|
||||
tzpath = os.path.join("/usr/share/zoneinfo/", timezone)
|
||||
@@ -58,7 +61,7 @@ def main() -> NoReturn:
|
||||
if location is None:
|
||||
cloudlog.debug("Setting timezone based on IP lookup")
|
||||
try:
|
||||
r = requests.get("https://ipapi.co/timezone", timeout=10)
|
||||
r = requests.get("https://ipapi.co/timezone", headers=REQUEST_HEADERS, timeout=10)
|
||||
if r.status_code == 200:
|
||||
set_timezone(valid_timezones, r.text)
|
||||
else:
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
import unittest
|
||||
import time
|
||||
import numpy as np
|
||||
@@ -9,6 +10,7 @@ from laika.opt import calc_pos_fix
|
||||
from openpilot.selfdrive.test.openpilotci import get_url
|
||||
from openpilot.tools.lib.logreader import LogReader
|
||||
from openpilot.selfdrive.test.helpers import with_processes
|
||||
from openpilot.selfdrive.test.helpers import temporary_dir
|
||||
import cereal.messaging as messaging
|
||||
|
||||
def get_gnss_measurements(log_reader):
|
||||
@@ -54,8 +56,9 @@ class TestUbloxProcessing(unittest.TestCase):
|
||||
self.assertEqual(count_gps, 5036)
|
||||
self.assertEqual(count_glonass, 3651)
|
||||
|
||||
def test_get_fix(self):
|
||||
dog = AstroDog()
|
||||
@temporary_dir
|
||||
def test_get_fix(self, temp_dir):
|
||||
dog = AstroDog(cache_dir=temp_dir)
|
||||
position_fix_found = 0
|
||||
count_processed_measurements = 0
|
||||
count_corrected_measurements = 0
|
||||
|
||||
Regular → Executable
Regular → Executable
@@ -108,37 +108,47 @@ export function createDummyVideoTrack() {
|
||||
export function start(pc, dc) {
|
||||
pc = createPeerConnection(pc);
|
||||
|
||||
if (constraints.audio || constraints.video) {
|
||||
// add audio track
|
||||
navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
|
||||
stream.getTracks().forEach(function(track) {
|
||||
pc.addTrack(track, stream);
|
||||
// only audio?
|
||||
// if (track.kind === 'audio'){
|
||||
// pc.addTrack(track, stream);
|
||||
// }
|
||||
});
|
||||
return negotiate(pc);
|
||||
}, function(err) {
|
||||
alert('Could not acquire media: ' + err);
|
||||
});
|
||||
// add audio track
|
||||
navigator.mediaDevices.enumerateDevices()
|
||||
.then(function(devices) {
|
||||
const hasAudioInput = devices.find((device) => { device.kind === "audioinput" });
|
||||
var modifiedConstraints = {};
|
||||
modifiedConstraints.video = constraints.video;
|
||||
modifiedConstraints.audio = hasAudioInput ? constraints.audio : false;
|
||||
|
||||
// add a fake video?
|
||||
// const dummyVideoTrack = createDummyVideoTrack();
|
||||
// const dummyMediaStream = new MediaStream();
|
||||
// dummyMediaStream.addTrack(dummyVideoTrack);
|
||||
// pc.addTrack(dummyVideoTrack, dummyMediaStream);
|
||||
return Promise.resolve(modifiedConstraints);
|
||||
})
|
||||
.then(function(constraints) {
|
||||
if (constraints.audio || constraints.video) {
|
||||
return navigator.mediaDevices.getUserMedia(constraints);
|
||||
} else{
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
})
|
||||
.then(function(stream) {
|
||||
if (stream) {
|
||||
stream.getTracks().forEach(function(track) {
|
||||
pc.addTrack(track, stream);
|
||||
});
|
||||
}
|
||||
|
||||
} else {
|
||||
negotiate(pc);
|
||||
}
|
||||
return negotiate(pc);
|
||||
})
|
||||
.catch(function(err) {
|
||||
alert('Could not acquire media: ' + err);
|
||||
});
|
||||
|
||||
// add a fake video?
|
||||
// const dummyVideoTrack = createDummyVideoTrack();
|
||||
// const dummyMediaStream = new MediaStream();
|
||||
// dummyMediaStream.addTrack(dummyVideoTrack);
|
||||
// pc.addTrack(dummyVideoTrack, dummyMediaStream);
|
||||
|
||||
// setInterval(() => {pc.getStats(null).then((stats) => {stats.forEach((report) => console.log(report))})}, 10000)
|
||||
// var video = document.querySelector('video');
|
||||
// var print = function (e, f){console.log(e, f); video.requestVideoFrameCallback(print);};
|
||||
// video.requestVideoFrameCallback(print);
|
||||
|
||||
|
||||
var parameters = {"ordered": true};
|
||||
dc = pc.createDataChannel('data', parameters);
|
||||
dc.onclose = function() {
|
||||
|
||||
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
+2
-2
@@ -32,7 +32,7 @@ class TestFileDownload(unittest.TestCase):
|
||||
self.assertEqual(response_cached, response_downloaded)
|
||||
|
||||
@temporary_cache_dir
|
||||
def test_small_file(self, temp_dir):
|
||||
def test_small_file(self):
|
||||
# Make sure we don't force cache
|
||||
os.environ["FILEREADER_CACHE"] = "0"
|
||||
small_file_url = "https://raw.githubusercontent.com/commaai/openpilot/master/docs/SAFETY.md"
|
||||
@@ -53,7 +53,7 @@ class TestFileDownload(unittest.TestCase):
|
||||
self.compare_loads(small_file_url, 100 * i, 100)
|
||||
|
||||
@temporary_cache_dir
|
||||
def test_large_file(self, temp_dir):
|
||||
def test_large_file(self):
|
||||
large_file_url = "https://commadataci.blob.core.windows.net/openpilotci/0375fdf7b1ce594d/2019-06-13--08-32-25/3/qlog.bz2"
|
||||
# Load the end 100 bytes of both files
|
||||
file_large = URLFile(large_file_url)
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
<tabbed_widget name="Main Window" parent="main_window">
|
||||
<Tab tab_name="tab1" containers="1">
|
||||
<Container>
|
||||
<DockSplitter orientation="-" sizes="0.333601;0.332799;0.333601" count="3">
|
||||
<DockSplitter orientation="-" sizes="0.250401;0.249599;0.250401;0.249599" count="4">
|
||||
<DockArea name="...">
|
||||
<plot flip_y="false" flip_x="false" mode="TimeSeries" style="Lines">
|
||||
<range right="60.000002" top="2.131164" left="0.000000" bottom="-3.377712"/>
|
||||
<range right="126.285782" top="1.391623" left="104.907277" bottom="-2.563614"/>
|
||||
<limitY/>
|
||||
<curve name="/carState/aEgo" color="#f14cc1"/>
|
||||
<curve name="/longitudinalPlan/accels/0" color="#9467bd"/>
|
||||
@@ -15,7 +15,16 @@
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot flip_y="false" flip_x="false" mode="TimeSeries" style="Lines">
|
||||
<range right="60.000002" top="19.304051" left="0.000000" bottom="-0.538805"/>
|
||||
<range right="126.285782" top="1.184960" left="104.907277" bottom="-1.811222" />
|
||||
<limitY/>
|
||||
<curve name="/controlsState/upAccelCmd" color="#1f77b4"/>
|
||||
<curve name="/controlsState/uiAccelCmd" color="#d62728"/>
|
||||
<curve name="/controlsState/ufAccelCmd" color="#1ac938"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot flip_y="false" flip_x="false" mode="TimeSeries" style="Lines">
|
||||
<range right="126.285782" top="15.862889" left="104.907277" bottom="-0.568809" />
|
||||
<limitY/>
|
||||
<curve name="/carState/vEgo" color="#1ac938"/>
|
||||
<curve name="/longitudinalPlan/speeds/0" color="#ff7f0e"/>
|
||||
@@ -23,7 +32,7 @@
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot flip_y="false" flip_x="false" mode="TimeSeries" style="Lines">
|
||||
<range right="60.000002" top="1.025000" left="0.000000" bottom="-0.025000"/>
|
||||
<range right="126.285782" top="1.025000" left="104.907277" bottom="-0.025000" />
|
||||
<limitY/>
|
||||
<curve name="/carControl/longActive" color="#1f77b4"/>
|
||||
<curve name="/carState/gasPressed" color="#d62728"/>
|
||||
|
||||
Regular → Executable
@@ -3,7 +3,7 @@
|
||||
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)"
|
||||
cd $DIR
|
||||
|
||||
OPENPILOT_DIR="/openpilot"
|
||||
OPENPILOT_DIR="/tmp/openpilot"
|
||||
if ! [[ -z "$MOUNT_OPENPILOT" ]]; then
|
||||
OPENPILOT_DIR="$(dirname $(dirname $DIR))"
|
||||
EXTRA_ARGS="-v $OPENPILOT_DIR:$OPENPILOT_DIR -e PYTHONPATH=$OPENPILOT_DIR:$PYTHONPATH"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#!/usr/bin/env python3
|
||||
import ft4222
|
||||
import ft4222.I2CMaster
|
||||
|
||||
|
||||
Reference in New Issue
Block a user