mirror of
https://github.com/infiniteCable2/opendbc.git
synced 2026-02-18 13:03:52 +08:00
Merge branch 'master' of https://github.com/sunnypilot/opendbc into sync
This commit is contained in:
36
.github/ISSUE_TEMPLATE/misc.yml
vendored
Normal file
36
.github/ISSUE_TEMPLATE/misc.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
name: Miscellaneous
|
||||
description: For tools or test bugs, or enhancements
|
||||
labels: ["bug"]
|
||||
body:
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: >
|
||||
* If the issue likely only affects your car model or make, go back and open a **car bug report** instead.
|
||||
Before creating a **miscellaneous bug report**, please check the following:
|
||||
* Ensure there isn't an existing issue for your bug. If there is, leave a comment on the existing issue.
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe the bug or enhancement
|
||||
description: Also include a description of how to reproduce the bug or how the enhancement would work
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: route
|
||||
attributes:
|
||||
label: Provide a route where the issue occurs if applicable
|
||||
description: Ensure the route is fully uploaded at https://useradmin.comma.ai
|
||||
placeholder: 77611a1fac303767|2020-05-11--16-37-07
|
||||
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: openpilot version if applicable
|
||||
description: If you're not on release, provide the commit hash
|
||||
placeholder: 0.8.10
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional info
|
||||
45
.github/workflows/car_diff.yml
vendored
Normal file
45
.github/workflows/car_diff.yml
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
name: car diff
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
comment:
|
||||
name: comment
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
actions: read
|
||||
steps:
|
||||
- name: Wait for car diff
|
||||
id: wait
|
||||
continue-on-error: true
|
||||
uses: lewagon/wait-on-check-action@v1.3.4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
check-name: car diff
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
allowed-conclusions: success
|
||||
wait-interval: 20
|
||||
- name: Download car diff
|
||||
if: steps.wait.outcome == 'success'
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
workflow: tests.yml
|
||||
workflow_conclusion: ''
|
||||
pr: ${{ github.event.number }}
|
||||
name: car_diff_${{ github.event.number }}
|
||||
path: .
|
||||
allow_forks: true
|
||||
- name: Comment car diff on PR
|
||||
if: steps.wait.outcome == 'success'
|
||||
uses: thollander/actions-comment-pull-request@v2
|
||||
with:
|
||||
filePath: diff.txt
|
||||
comment_tag: car_diff
|
||||
pr_number: ${{ github.event.number }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
10
.github/workflows/tests.yml
vendored
10
.github/workflows/tests.yml
vendored
@@ -62,6 +62,7 @@ jobs:
|
||||
|
||||
car_diff:
|
||||
name: car diff
|
||||
if: false
|
||||
runs-on: ${{ github.repository == 'commaai/opendbc' && 'namespace-profile-amd64-8x16' || 'ubuntu-latest' }}
|
||||
env:
|
||||
GIT_REF: ${{ github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && github.event.before || format('origin/{0}', github.event.repository.default_branch) }}
|
||||
@@ -77,11 +78,12 @@ jobs:
|
||||
- name: Test car diff
|
||||
if: github.event_name == 'pull_request'
|
||||
run: source setup.sh && python opendbc/car/tests/car_diff.py | tee diff.txt
|
||||
- name: Comment PR
|
||||
- name: Upload diff
|
||||
if: always() && github.event_name == 'pull_request' && github.repository == 'commaai/opendbc'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: '[ -s diff.txt ] && gh pr comment ${{ github.event.pull_request.number }} --repo ${{ github.repository }} -F diff.txt || true'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: car_diff_${{ github.event.number }}
|
||||
path: diff.txt
|
||||
- name: Update refs
|
||||
if: github.repository == 'commaai/opendbc' && github.ref == 'refs/heads/master'
|
||||
run: source setup.sh && python opendbc/car/tests/car_diff.py --update-refs
|
||||
|
||||
2
.github/workflows/update-cars-docs.yml
vendored
2
.github/workflows/update-cars-docs.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
run: |
|
||||
pip install -e .
|
||||
scons -c && scons -j$(nproc)
|
||||
python -m pip install jinja2==3.1.4 natsort==8.4.0
|
||||
python -m pip install jinja2==3.1.4
|
||||
python opendbc/car/docs.py
|
||||
- uses: stefanzweifel/git-auto-commit-action@8621497c8c39c72f3e2a999a26b4ca1b5058a842
|
||||
with:
|
||||
|
||||
30
.github/workflows/update-uv-lock.yml
vendored
Normal file
30
.github/workflows/update-uv-lock.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
name: Update uv.lock
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 14 * * 1" # every Monday at 2am UTC (6am PST)
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
update-uv-lock:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: astral-sh/setup-uv@v5
|
||||
- name: Update uv.lock
|
||||
run: uv lock --upgrade
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@9153d834b60caba6d51c9b9510b087acf9f33f83
|
||||
with:
|
||||
author: Vehicle Researcher <user@comma.ai>
|
||||
token: ${{ secrets.ACTIONS_CREATE_PR_PAT }}
|
||||
commit-message: "[bot] Update uv.lock"
|
||||
title: "[bot] Update uv.lock"
|
||||
body: "Weekly update of uv.lock dependencies"
|
||||
branch: "update-uv-lock"
|
||||
base: "master"
|
||||
delete-branch: true
|
||||
labels: bot
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -17,7 +17,6 @@
|
||||
*.gcno
|
||||
*.dump
|
||||
*.gcov
|
||||
uv.lock
|
||||
/dist/
|
||||
.vscode/
|
||||
__pycache__/
|
||||
|
||||
72
docs/CARS.md
72
docs/CARS.md
@@ -1,16 +1,18 @@
|
||||
<!--- AUTOGENERATED FROM selfdrive/car/CARS_template.md, DO NOT EDIT. --->
|
||||
|
||||
# Support Information for 384 Known Cars
|
||||
# Support Information for 410 Known Cars
|
||||
|
||||
|Make|Model|Package|Support Level|
|
||||
|---|---|---|:---:|
|
||||
|Acura|ADX 2025-26|All|[Community](#community)|
|
||||
|Acura|ILX 2016-18|Technology Plus Package or AcuraWatch Plus|[Upstream](#upstream)|
|
||||
|Acura|ILX 2019|All|[Upstream](#upstream)|
|
||||
|Acura|Integra 2023-25|All|[Community](#community)|
|
||||
|Acura|MDX 2015-16|Advance Package|[Community](#community)|
|
||||
|Acura|MDX 2017-20|All|[Community](#community)|
|
||||
|Acura|MDX 2022-24|All|[Community](#community)|
|
||||
|Acura|MDX 2025|All except Type S|[Upstream](#upstream)|
|
||||
|Acura|MDX 2025-26|All except Type S|[Upstream](#upstream)|
|
||||
|Acura|MDX Hybrid 2017-20|All|[Community](#community)|
|
||||
|Acura|RDX 2016-18|AcuraWatch Plus or Advance Package|[Upstream](#upstream)|
|
||||
|Acura|RDX 2019-21|All|[Upstream](#upstream)|
|
||||
|Acura|RDX 2022-25|All|[Community](#community)|
|
||||
@@ -19,6 +21,7 @@
|
||||
|Acura|TLX 2018-20|All|[Community](#community)|
|
||||
|Acura|TLX 2021|All|[Upstream](#upstream)|
|
||||
|Acura|TLX 2022-23|All|[Community](#community)|
|
||||
|Acura|TLX 2025|All|[Upstream](#upstream)|
|
||||
|Acura|ZDX 2024|All|[Not compatible](#can-bus-security)|
|
||||
|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
@@ -29,11 +32,21 @@
|
||||
|Audi|Q5 2017-24|All|[Not compatible](#flexray)|
|
||||
|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Cadillac|CT6 Non-ACC 2017-18|No Adaptive Cruise Control (Non-ACC)|[Dashcam mode](#dashcam)|
|
||||
|Cadillac|XT5 Non-ACC 2018|No Adaptive Cruise Control (Non-ACC)|[Dashcam mode](#dashcam)|
|
||||
|Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim, without Super Cruise Package|[Upstream](#upstream)|
|
||||
|Chevrolet|Bolt EUV LT Non-ACC 2022-23|No Adaptive Cruise Control (Non-ACC)|[Dashcam mode](#dashcam)|
|
||||
|Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|[Upstream](#upstream)|
|
||||
|Chevrolet|Bolt EV LT Non-ACC 2022-23|No Adaptive Cruise Control (Non-ACC)|[Dashcam mode](#dashcam)|
|
||||
|Chevrolet|Bolt EV Non-ACC 2017|No Adaptive Cruise Control (Non-ACC)|[Community](community)|
|
||||
|Chevrolet|Bolt EV Non-ACC 2018-21|No Adaptive Cruise Control (Non-ACC)|[Community](community)|
|
||||
|Chevrolet|Equinox 2019-22|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Chevrolet|Equinox Non-ACC 2019-22|No Adaptive Cruise Control (Non-ACC)|[Dashcam mode](#dashcam)|
|
||||
|Chevrolet|Malibu Non-ACC 2016-23|No Adaptive Cruise Control (Non-ACC)|[Community](community)|
|
||||
|Chevrolet|Silverado 1500 2020-21|Safety Package II|[Upstream](#upstream)|
|
||||
|Chevrolet|Suburban Non-ACC 2016-20|No Adaptive Cruise Control (Non-ACC)|[Dashcam mode](#dashcam)|
|
||||
|Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Chevrolet|Trailblazer Non-ACC 2021-22|No Adaptive Cruise Control (Non-ACC)|[Dashcam mode](#dashcam)|
|
||||
|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Chrysler|Pacifica 2021-23|All|[Upstream](#upstream)|
|
||||
@@ -70,6 +83,7 @@
|
||||
|Genesis|G70 2018|All|[Upstream](#upstream)|
|
||||
|Genesis|G70 2019-21|All|[Upstream](#upstream)|
|
||||
|Genesis|G70 2022-23|All|[Upstream](#upstream)|
|
||||
|Genesis|G70 Non-SCC 2021|No Smart Cruise Control (Non-SCC)|[Dashcam mode](#dashcam)|
|
||||
|Genesis|G80 2017|All|[Upstream](#upstream)|
|
||||
|Genesis|G80 2018-19|All|[Upstream](#upstream)|
|
||||
|Genesis|G80 (2.5T Advanced Trim, with HDA II) 2024|Highway Driving Assist II|[Upstream](#upstream)|
|
||||
@@ -86,6 +100,7 @@
|
||||
|Honda|Accord 2016-17|Honda Sensing|[Community](#community)|
|
||||
|Honda|Accord 2018-22|All|[Upstream](#upstream)|
|
||||
|Honda|Accord 2023-25|All|[Upstream](#upstream)|
|
||||
|Honda|Accord Hybrid 2017|All|[Community](#community)|
|
||||
|Honda|Accord Hybrid 2018-22|All|[Upstream](#upstream)|
|
||||
|Honda|Accord Hybrid 2023-25|All|[Upstream](#upstream)|
|
||||
|Honda|City (Brazil only) 2023|All|[Upstream](#upstream)|
|
||||
@@ -98,12 +113,13 @@
|
||||
|Honda|Civic Hatchback Hybrid 2025-26|All|[Upstream](#upstream)|
|
||||
|Honda|Civic Hatchback Hybrid (Europe only) 2023|All|[Upstream](#upstream)|
|
||||
|Honda|Civic Hybrid 2025-26|All|[Upstream](#upstream)|
|
||||
|Honda|Clarity 2018-21|Honda Sensing|[Community](community)|
|
||||
|Honda|Clarity 2018-21|All|[Community](#community)|
|
||||
|Honda|CR-V 2015-16|Touring Trim|[Upstream](#upstream)|
|
||||
|Honda|CR-V 2017-22|Honda Sensing|[Upstream](#upstream)|
|
||||
|Honda|CR-V 2023-26|All|[Upstream](#upstream)|
|
||||
|Honda|CR-V Hybrid 2017-22|Honda Sensing|[Upstream](#upstream)|
|
||||
|Honda|CR-V Hybrid 2023-25|All|[Upstream](#upstream)|
|
||||
|Honda|CR-V Hybrid 2023-26|All|[Upstream](#upstream)|
|
||||
|Honda|e 2020|All|[Upstream](#upstream)|
|
||||
|Honda|Fit 2018-20|Honda Sensing|[Upstream](#upstream)|
|
||||
|Honda|Freed 2020|Honda Sensing|[Upstream](#upstream)|
|
||||
@@ -114,6 +130,7 @@
|
||||
|Honda|N-Box 2018|All|[Upstream](#upstream)|
|
||||
|Honda|Odyssey 2018-20|Honda Sensing|[Upstream](#upstream)|
|
||||
|Honda|Odyssey 2021-26|All|[Upstream](#upstream)|
|
||||
|Honda|Odyssey (Taiwan) 2018-19|Honda Sensing|[Upstream](#upstream)|
|
||||
|Honda|Passport 2019-25|All|[Upstream](#upstream)|
|
||||
|Honda|Passport 2026|All|[Upstream](#upstream)|
|
||||
|Honda|Pilot 2016-22|Honda Sensing|[Upstream](#upstream)|
|
||||
@@ -123,12 +140,14 @@
|
||||
|Hyundai|Azera 2022|All|[Upstream](#upstream)|
|
||||
|Hyundai|Azera Hybrid 2019|All|[Upstream](#upstream)|
|
||||
|Hyundai|Azera Hybrid 2020|All|[Upstream](#upstream)|
|
||||
|Hyundai|Bayon Non-SCC 2021|No Smart Cruise Control (Non-SCC)|[Dashcam mode](#dashcam)|
|
||||
|Hyundai|Custin 2023|All|[Upstream](#upstream)|
|
||||
|Hyundai|Elantra 2017-18|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Elantra 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Elantra 2021-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Elantra GT 2017-20|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Elantra Non-SCC 2022|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||
|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Ioniq 5 (Southeast Asia and Europe only) 2022-24|All|[Upstream](#upstream)|
|
||||
@@ -142,14 +161,16 @@
|
||||
|Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Ioniq Plug-in Hybrid 2020-22|All|[Upstream](#upstream)|
|
||||
|Hyundai|Kona 2020|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Kona 2022-23|Smart Cruise Control (SCC)|[Dashcam mode](#dashcam)|
|
||||
|Hyundai|Kona 2022-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Kona Electric 2022-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Kona Electric (with HDA II, Korea only) 2023|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Kona Electric Non-SCC 2019|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||
|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Kona Non-SCC 2019|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||
|Hyundai|Nexo 2021|All|[Upstream](#upstream)|
|
||||
|Hyundai|Palisade 2020-22|All|[Upstream](#upstream)|
|
||||
|Hyundai|Palisade 2023-24|HDA2|[Community](#community)|
|
||||
|Hyundai|Palisade 2023-24|Highway Driving Assist II|[Community](#community)|
|
||||
|Hyundai|Santa Cruz 2022-24|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Santa Fe 2019-20|All|[Upstream](#upstream)|
|
||||
|Hyundai|Santa Fe 2021-23|All|[Upstream](#upstream)|
|
||||
@@ -171,11 +192,14 @@
|
||||
|Kia|Carnival 2022-24|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Carnival (China only) 2023|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Ceed 2019-21|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Ceed Plug-in Hybrid Non-SCC 2022|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||
|Kia|EV6 (Southeast Asia only) 2022-24|All|[Upstream](#upstream)|
|
||||
|Kia|EV6 (with HDA II) 2022-24|Highway Driving Assist II|[Upstream](#upstream)|
|
||||
|Kia|EV6 (without HDA II) 2022-24|Highway Driving Assist|[Upstream](#upstream)|
|
||||
|Kia|Forte 2019-21|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Forte 2022-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Forte Non-SCC 2019|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||
|Kia|Forte Non-SCC 2021|No Smart Cruise Control (Non-SCC)|[Dashcam mode](#dashcam)|
|
||||
|Kia|K5 2021-24|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|K5 Hybrid 2020-22|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|K8 Hybrid (with HDA II) 2023|Highway Driving Assist II|[Upstream](#upstream)|
|
||||
@@ -198,6 +222,7 @@
|
||||
|Kia|Optima Hybrid 2017|Advanced Smart Cruise Control|[Dashcam mode](#dashcam)|
|
||||
|Kia|Optima Hybrid 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Seltos 2021|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Seltos Non-SCC 2023-24|No Smart Cruise Control (Non-SCC)|[Dashcam mode](#dashcam)|
|
||||
|Kia|Sorento 2018|Advanced Smart Cruise Control & LKAS|[Upstream](#upstream)|
|
||||
|Kia|Sorento 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Sorento 2021-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
@@ -208,7 +233,7 @@
|
||||
|Kia|Stinger 2018-20|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Stinger 2022-23|All|[Upstream](#upstream)|
|
||||
|Kia|Telluride 2020-22|All|[Upstream](#upstream)|
|
||||
|Kia|Telluride 2023-24|HDA2|[Community](#community)|
|
||||
|Kia|Telluride 2023-24|Highway Driving Assist II|[Community](#community)|
|
||||
|Lexus|CT Hybrid 2017-18|Lexus Safety System+|[Upstream](#upstream)|
|
||||
|Lexus|ES 2017-18|All|[Upstream](#upstream)|
|
||||
|Lexus|ES 2019-25|All|[Upstream](#upstream)|
|
||||
@@ -218,7 +243,8 @@
|
||||
|Lexus|IS 2017-19|All|[Upstream](#upstream)|
|
||||
|Lexus|IS 2022-24|All|[Upstream](#upstream)|
|
||||
|Lexus|LC 2024-25|All|[Upstream](#upstream)|
|
||||
|Lexus|NS 2022-25|Any|[Not compatible](#can-bus-security)|
|
||||
|Lexus|LS 2018|All except Lexus Safety System+ A|[Upstream](#upstream)|
|
||||
|Lexus|NS 2022-25|All|[Not compatible](#can-bus-security)|
|
||||
|Lexus|NX 2018-19|All|[Upstream](#upstream)|
|
||||
|Lexus|NX 2020-21|All|[Upstream](#upstream)|
|
||||
|Lexus|NX Hybrid 2018-19|All|[Upstream](#upstream)|
|
||||
@@ -249,8 +275,8 @@
|
||||
|Peugeot|208 2019-25|Adaptive Cruise Control (ACC) & Lane Assist|[Dashcam mode](#dashcam)|
|
||||
|Porsche|Macan 2017-24|Adaptive Cruise Control (ACC) & Lane Assist|[Dashcam mode](#dashcam)|
|
||||
|Ram|1500 2019-24|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Ram|2500 2020-24|Adaptive Cruise Control (ACC)|[Dashcam mode](#dashcam)|
|
||||
|Ram|3500 2019-22|Adaptive Cruise Control (ACC)|[Dashcam mode](#dashcam)|
|
||||
|Ram|2500 2020-24|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Ram|3500 2019-22|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Rivian|R1S 2022-24|All|[Upstream](#upstream)|
|
||||
|Rivian|R1T 2022-24|All|[Upstream](#upstream)|
|
||||
|SEAT|Alhambra 2018-20|Adaptive Cruise Control (ACC) & Lane Assist|[Dashcam mode](#dashcam)|
|
||||
@@ -261,19 +287,19 @@
|
||||
|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||
|Subaru|Crosstrek 2020-23|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||
|Subaru|Crosstrek Hybrid 2020|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|
||||
|Subaru|Forester 2017-18|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|
||||
|Subaru|Forester 2017-18|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||
|Subaru|Forester 2019-21|All|[Upstream](#upstream)|
|
||||
|Subaru|Forester 2022-24|All|[Dashcam mode](#dashcam)|
|
||||
|Subaru|Forester Hybrid 2020|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|
||||
|Subaru|Impreza 2017-19|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||
|Subaru|Impreza 2020-22|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||
|Subaru|Legacy 2015-18|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|
||||
|Subaru|Legacy 2015-18|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||
|Subaru|Legacy 2020-22|All|[Upstream](#upstream)|
|
||||
|Subaru|Outback 2015-17|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|
||||
|Subaru|Outback 2018-19|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|
||||
|Subaru|Outback 2015-17|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||
|Subaru|Outback 2018-19|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||
|Subaru|Outback 2020-22|All|[Upstream](#upstream)|
|
||||
|Subaru|Outback 2023|All|[Dashcam mode](#dashcam)|
|
||||
|Subaru|Solterra 2023-25|Any|[Not compatible](#can-bus-security)|
|
||||
|Subaru|Solterra 2023-25|All|[Not compatible](#can-bus-security)|
|
||||
|Subaru|XV 2018-19|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||
|Subaru|XV 2020-21|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||
|Škoda|Fabia 2022-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
@@ -298,19 +324,19 @@
|
||||
|Toyota|Avalon 2022|All|[Upstream](#upstream)|
|
||||
|Toyota|Avalon Hybrid 2019-21|All|[Upstream](#upstream)|
|
||||
|Toyota|Avalon Hybrid 2022|All|[Upstream](#upstream)|
|
||||
|Toyota|bZ4x 2023-25|Any|[Not compatible](#can-bus-security)|
|
||||
|Toyota|bZ4x 2023-25|All|[Not compatible](#can-bus-security)|
|
||||
|Toyota|C-HR 2017-20|All|[Upstream](#upstream)|
|
||||
|Toyota|C-HR 2021|All|[Upstream](#upstream)|
|
||||
|Toyota|C-HR Hybrid 2017-20|All|[Upstream](#upstream)|
|
||||
|Toyota|C-HR Hybrid 2021-22|All|[Upstream](#upstream)|
|
||||
|Toyota|Camry 2018-20|All|[Upstream](#upstream)|
|
||||
|Toyota|Camry 2021-24|All|[Upstream](#upstream)|
|
||||
|Toyota|Camry 2025|Any|[Not compatible](#can-bus-security)|
|
||||
|Toyota|Camry 2025|All|[Not compatible](#can-bus-security)|
|
||||
|Toyota|Camry Hybrid 2018-20|All|[Upstream](#upstream)|
|
||||
|Toyota|Camry Hybrid 2021-24|All|[Upstream](#upstream)|
|
||||
|Toyota|Corolla 2017-19|All|[Upstream](#upstream)|
|
||||
|Toyota|Corolla 2020-22|All|[Upstream](#upstream)|
|
||||
|Toyota|Corolla Cross 2022-25|Any|[Not compatible](#can-bus-security)|
|
||||
|Toyota|Corolla Cross 2022-25|All|[Not compatible](#can-bus-security)|
|
||||
|Toyota|Corolla Cross (Non-US only) 2020-23|All|[Upstream](#upstream)|
|
||||
|Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|[Upstream](#upstream)|
|
||||
|Toyota|Corolla Hatchback 2019-22|All|[Upstream](#upstream)|
|
||||
@@ -318,7 +344,7 @@
|
||||
|Toyota|Corolla Hybrid (South America only) 2020-23|All|[Upstream](#upstream)|
|
||||
|Toyota|Highlander 2017-19|All|[Upstream](#upstream)|
|
||||
|Toyota|Highlander 2020-23|All|[Upstream](#upstream)|
|
||||
|Toyota|Highlander 2025|Any|[Not compatible](#can-bus-security)|
|
||||
|Toyota|Highlander 2025|All|[Not compatible](#can-bus-security)|
|
||||
|Toyota|Highlander Hybrid 2017-19|All|[Upstream](#upstream)|
|
||||
|Toyota|Highlander Hybrid 2020-23|All|[Upstream](#upstream)|
|
||||
|Toyota|Mirai 2021|All|[Upstream](#upstream)|
|
||||
@@ -339,13 +365,13 @@
|
||||
|Toyota|RAV4 Hybrid 2022|All|[Upstream](#upstream)|
|
||||
|Toyota|RAV4 Hybrid 2023-25|All|[Upstream](#upstream)|
|
||||
|Toyota|RAV4 Prime 2021-23|All|[Custom](#secoc-cars-with-recoverable-keys)|
|
||||
|Toyota|RAV4 Prime 2024-25|Any|[Not compatible](#can-bus-security)|
|
||||
|Toyota|Sequoia 2023-25|Any|[Not compatible](#can-bus-security)|
|
||||
|Toyota|RAV4 Prime 2024-25|All|[Not compatible](#can-bus-security)|
|
||||
|Toyota|Sequoia 2023-25|All|[Not compatible](#can-bus-security)|
|
||||
|Toyota|Sienna 2018-20|All|[Upstream](#upstream)|
|
||||
|Toyota|Sienna 2021-23|All|[Custom](#secoc-cars-with-recoverable-keys)|
|
||||
|Toyota|Sienna 2024-25|Any|[Not compatible](#can-bus-security)|
|
||||
|Toyota|Tundra 2022-25|Any|[Not compatible](#can-bus-security)|
|
||||
|Toyota|Venza 2021-25|Any|[Not compatible](#can-bus-security)|
|
||||
|Toyota|Sienna 2024-25|All|[Not compatible](#can-bus-security)|
|
||||
|Toyota|Tundra 2022-25|All|[Not compatible](#can-bus-security)|
|
||||
|Toyota|Venza 2021-25|All|[Not compatible](#can-bus-security)|
|
||||
|Toyota|Yaris (Non-US only) 2020, 2023|All|[Custom](#secoc-cars-with-recoverable-keys)|
|
||||
|Volkswagen|Arteon 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Arteon eHybrid 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|
||||
@@ -130,17 +130,15 @@ class CanSignalRateCalculator:
|
||||
Calculates the instantaneous rate of a CAN signal by using the counter
|
||||
variable and the known frequency of the CAN message that contains it.
|
||||
"""
|
||||
def __init__(self, frequency):
|
||||
def __init__(self, frequency: int):
|
||||
self.frequency = frequency
|
||||
self.previous_counter = 0
|
||||
self.previous_value = 0
|
||||
self.rate = 0
|
||||
|
||||
def update(self, current_value, current_counter):
|
||||
if current_counter != self.previous_counter:
|
||||
def update(self, current_value: float, updated: bool):
|
||||
if updated:
|
||||
self.rate = (current_value - self.previous_value) * self.frequency
|
||||
|
||||
self.previous_counter = current_counter
|
||||
self.previous_value = current_value
|
||||
|
||||
return self.rate
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
from opendbc.car.crc import CRC8BODY
|
||||
|
||||
|
||||
def create_control(packer, torque_l, torque_r):
|
||||
values = {
|
||||
"TORQUE_L": torque_l,
|
||||
@@ -9,12 +12,6 @@ def create_control(packer, torque_l, torque_r):
|
||||
|
||||
def body_checksum(address: int, sig, d: bytearray) -> int:
|
||||
crc = 0xFF
|
||||
poly = 0xD5
|
||||
for i in range(len(d) - 2, -1, -1):
|
||||
crc ^= d[i]
|
||||
for _ in range(8):
|
||||
if crc & 0x80:
|
||||
crc = ((crc << 1) ^ poly) & 0xFF
|
||||
else:
|
||||
crc = (crc << 1) & 0xFF
|
||||
crc = CRC8BODY[crc ^ d[i]]
|
||||
return crc
|
||||
|
||||
@@ -217,7 +217,7 @@ class CcpClient:
|
||||
resp = self._recv_dto(0.025)
|
||||
# mta_addr_ext = resp[0]
|
||||
mta_addr = struct.unpack(f"{self.byte_order.value}I", resp[1:5])[0]
|
||||
return mta_addr # type: ignore
|
||||
return mta_addr
|
||||
|
||||
def download_6_bytes(self, data: bytes) -> int:
|
||||
if len(data) != 6:
|
||||
@@ -226,7 +226,7 @@ class CcpClient:
|
||||
resp = self._recv_dto(0.025)
|
||||
# mta_addr_ext = resp[0]
|
||||
mta_addr = struct.unpack(f"{self.byte_order.value}I", resp[1:5])[0]
|
||||
return mta_addr # type: ignore
|
||||
return mta_addr
|
||||
|
||||
def upload(self, size: int) -> bytes:
|
||||
if size > 5:
|
||||
@@ -325,7 +325,7 @@ class CcpClient:
|
||||
resp = self._recv_dto(0.1)
|
||||
# mta_addr_ext = resp[0]
|
||||
mta_addr = struct.unpack(f"{self.byte_order.value}I", resp[1:5])[0]
|
||||
return mta_addr # type: ignore
|
||||
return mta_addr
|
||||
|
||||
def program_6_bytes(self, data: bytes) -> int:
|
||||
if len(data) != 6:
|
||||
@@ -334,7 +334,7 @@ class CcpClient:
|
||||
resp = self._recv_dto(0.1)
|
||||
# mta_addr_ext = resp[0]
|
||||
mta_addr = struct.unpack(f"{self.byte_order.value}I", resp[1:5])[0]
|
||||
return mta_addr # type: ignore
|
||||
return mta_addr
|
||||
|
||||
def move_memory_block(self, size: int) -> None:
|
||||
self._send_cro(COMMAND_CODE.MOVE, struct.pack(f"{self.byte_order.value}I", size))
|
||||
|
||||
@@ -73,8 +73,8 @@ class RadarInterface(RadarInterfaceBase):
|
||||
if 'LONG_DIST' in cpt: # c_* message
|
||||
self.pts[trackId].dRel = cpt['LONG_DIST'] # from front of car
|
||||
# our lat_dist is positive to the right in car's frame.
|
||||
# TODO what does yRel want?
|
||||
self.pts[trackId].yRel = cpt['LAT_DIST'] # in car frame's y axis, left is positive
|
||||
# LAT_DIST is right-positive, yRel is left-positive
|
||||
self.pts[trackId].yRel = -cpt['LAT_DIST'] # in car frame's y axis, left is positive
|
||||
else: # d_* message
|
||||
self.pts[trackId].vRel = cpt['REL_SPEED']
|
||||
|
||||
|
||||
@@ -27,4 +27,5 @@ def _gen_crc16_table(poly: int) -> list[int]:
|
||||
|
||||
CRC8H2F = _gen_crc8_table(0x2F)
|
||||
CRC8J1850 = _gen_crc8_table(0x1D)
|
||||
CRC8BODY = _gen_crc8_table(0xD5)
|
||||
CRC16_XMODEM = _gen_crc16_table(0x1021)
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import re
|
||||
import os
|
||||
import jinja2
|
||||
import argparse
|
||||
import unicodedata
|
||||
from typing import get_args
|
||||
|
||||
from collections import defaultdict
|
||||
import jinja2
|
||||
from enum import Enum
|
||||
from natsort import natsorted
|
||||
from collections import defaultdict
|
||||
|
||||
from opendbc.car.common.basedir import BASEDIR
|
||||
from opendbc.car import gen_empty_fingerprint
|
||||
@@ -47,6 +48,12 @@ def get_all_footnotes() -> dict[Enum, int]:
|
||||
return {fn: idx + 1 for idx, fn in enumerate(all_footnotes)}
|
||||
|
||||
|
||||
def _natural_sort_key(s):
|
||||
# NFKD normalization ensures accented characters sort with their base letter (e.g., Š sorts with S)
|
||||
normalized = unicodedata.normalize('NFKD', s)
|
||||
return [int(t) if t.isdigit() else t.lower() for t in re.split(r'(\d+)', normalized) if t]
|
||||
|
||||
|
||||
def build_sorted_car_docs_list(platforms, footnotes=None):
|
||||
collected_car_docs: list[CarDocs | ExtraCarDocs] = []
|
||||
for platform in platforms.values():
|
||||
@@ -64,7 +71,7 @@ def build_sorted_car_docs_list(platforms, footnotes=None):
|
||||
collected_car_docs.append(_car_docs)
|
||||
|
||||
# Sort cars by make and model + year
|
||||
sorted_cars = natsorted(collected_car_docs, key=lambda car: car.name.lower())
|
||||
sorted_cars = sorted(collected_car_docs, key=lambda car: _natural_sort_key(car.name))
|
||||
return sorted_cars
|
||||
|
||||
|
||||
|
||||
@@ -37,9 +37,11 @@ class CAR(Platforms):
|
||||
|
||||
EXTRA_HONDA = ExtraPlatformConfig(
|
||||
[
|
||||
CommunityCarDocs("Acura ADX 2025-26"),
|
||||
CommunityCarDocs("Acura Integra 2023-25"),
|
||||
CommunityCarDocs("Acura MDX 2015-16", "Advance Package"),
|
||||
CommunityCarDocs("Acura MDX 2017-20"),
|
||||
CommunityCarDocs("Acura MDX Hybrid 2017-20"),
|
||||
CommunityCarDocs("Acura MDX 2022-24"),
|
||||
CommunityCarDocs("Acura RDX 2022-25"),
|
||||
CommunityCarDocs("Acura RLX 2017", "Advance Package or Technology Package"),
|
||||
@@ -48,6 +50,7 @@ class CAR(Platforms):
|
||||
CommunityCarDocs("Acura TLX 2022-23"),
|
||||
GMSecurityCarDocs("Acura ZDX 2024"),
|
||||
CommunityCarDocs("Honda Accord 2016-17", "Honda Sensing"),
|
||||
CommunityCarDocs("Honda Accord Hybrid 2017"),
|
||||
CommunityCarDocs("Honda Clarity 2018-21"),
|
||||
GMSecurityCarDocs("Honda Prologue 2024-25"),
|
||||
],
|
||||
@@ -55,8 +58,8 @@ class CAR(Platforms):
|
||||
|
||||
EXTRA_HYUNDAI = ExtraPlatformConfig(
|
||||
[
|
||||
CommunityCarDocs("Hyundai Palisade 2023-24", package="HDA2"),
|
||||
CommunityCarDocs("Kia Telluride 2023-24", package="HDA2"),
|
||||
CommunityCarDocs("Hyundai Palisade 2023-24", "Highway Driving Assist II"),
|
||||
CommunityCarDocs("Kia Telluride 2023-24", "Highway Driving Assist II"),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ from enum import Enum, IntFlag
|
||||
|
||||
from opendbc.car import Bus, PlatformConfig, DbcDict, Platforms, CarSpecs
|
||||
from opendbc.car.structs import CarParams
|
||||
from opendbc.car.docs_definitions import CarDocs, CarFootnote, CarHarness, CarParts, Column
|
||||
from opendbc.car.docs_definitions import CarDocs, CarFootnote, CarHarness, CarParts, Column, SupportType
|
||||
from opendbc.car.fw_query_definitions import FwQueryConfig, Request, StdQueries
|
||||
|
||||
from opendbc.sunnypilot.car.gm.values_ext import GMFlagsSP
|
||||
@@ -88,6 +88,13 @@ class GMCarDocs(CarDocs):
|
||||
self.car_parts = CarParts.common([CarHarness.obd_ii])
|
||||
|
||||
|
||||
@dataclass
|
||||
class GMNonAccCarDocs(GMCarDocs):
|
||||
package: str = "No Adaptive Cruise Control (Non-ACC)"
|
||||
support_type: SupportType = SupportType.COMMUNITY
|
||||
support_link: str = "community"
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class GMCarSpecs(CarSpecs):
|
||||
tireStiffnessFactor: float = 0.444 # not optimized yet
|
||||
@@ -116,6 +123,12 @@ class GMSDGMPlatformConfig(GMPlatformConfig):
|
||||
self.car_docs = []
|
||||
|
||||
|
||||
@dataclass
|
||||
class GMNonSccPlatformConfig(GMPlatformConfig):
|
||||
def init(self):
|
||||
self.sp_flags |= GMFlagsSP.NON_ACC
|
||||
|
||||
|
||||
class CAR(Platforms):
|
||||
HOLDEN_ASTRA = GMASCMPlatformConfig(
|
||||
[GMCarDocs("Holden Astra 2017")],
|
||||
@@ -199,58 +212,48 @@ class CAR(Platforms):
|
||||
# port extensions
|
||||
# Separate car def is required when there is no ASCM
|
||||
# (for now) unless there is a way to detect it when it has been unplugged...
|
||||
# CHEVROLET_VOLT_CC = GMPlatformConfig(
|
||||
# [GMCarDocs("Chevrolet Volt LT 2017-18")],
|
||||
# CHEVROLET_VOLT_CC = GMNonSccPlatformConfig(
|
||||
# [GMNonAccCarDocs("Chevrolet Volt LT 2017-18")],
|
||||
# CHEVROLET_VOLT.specs,
|
||||
# sp_flags=GMFlagsSP.NON_ACC,
|
||||
# )
|
||||
CHEVROLET_BOLT_NON_ACC = GMPlatformConfig(
|
||||
[GMCarDocs("Chevrolet Bolt EV Non-ACC 2017")],
|
||||
CHEVROLET_BOLT_NON_ACC = GMNonSccPlatformConfig(
|
||||
[GMNonAccCarDocs("Chevrolet Bolt EV Non-ACC 2017")],
|
||||
CHEVROLET_BOLT_EUV.specs,
|
||||
sp_flags=GMFlagsSP.NON_ACC,
|
||||
)
|
||||
CHEVROLET_BOLT_NON_ACC_1ST_GEN = GMPlatformConfig(
|
||||
[GMCarDocs("Chevrolet Bolt EV Non-ACC 2018-21")],
|
||||
CHEVROLET_BOLT_NON_ACC_1ST_GEN = GMNonSccPlatformConfig(
|
||||
[GMNonAccCarDocs("Chevrolet Bolt EV Non-ACC 2018-21")],
|
||||
CHEVROLET_BOLT_EUV.specs,
|
||||
sp_flags=GMFlagsSP.NON_ACC,
|
||||
)
|
||||
CHEVROLET_BOLT_NON_ACC_2ND_GEN = GMPlatformConfig(
|
||||
CHEVROLET_BOLT_NON_ACC_2ND_GEN = GMNonSccPlatformConfig(
|
||||
[
|
||||
GMCarDocs("Chevrolet Bolt EUV LT Non-ACC 2022-23"),
|
||||
GMCarDocs("Chevrolet Bolt EV LT Non-ACC 2022-23"),
|
||||
GMNonAccCarDocs("Chevrolet Bolt EUV LT Non-ACC 2022-23"),
|
||||
GMNonAccCarDocs("Chevrolet Bolt EV LT Non-ACC 2022-23"),
|
||||
],
|
||||
CHEVROLET_BOLT_EUV.specs,
|
||||
sp_flags=GMFlagsSP.NON_ACC,
|
||||
)
|
||||
CHEVROLET_EQUINOX_NON_ACC_3RD_GEN = GMPlatformConfig(
|
||||
[GMCarDocs("Chevrolet Equinox Non-ACC 2019-22")],
|
||||
CHEVROLET_EQUINOX_NON_ACC_3RD_GEN = GMNonSccPlatformConfig(
|
||||
[GMNonAccCarDocs("Chevrolet Equinox Non-ACC 2019-22")],
|
||||
CHEVROLET_EQUINOX.specs,
|
||||
sp_flags=GMFlagsSP.NON_ACC,
|
||||
)
|
||||
CHEVROLET_SUBURBAN_NON_ACC_11TH_GEN = GMPlatformConfig(
|
||||
[GMCarDocs("Chevrolet Suburban Non-ACC 2016-20")],
|
||||
CHEVROLET_SUBURBAN_NON_ACC_11TH_GEN = GMNonSccPlatformConfig(
|
||||
[GMNonAccCarDocs("Chevrolet Suburban Non-ACC 2016-20")],
|
||||
CarSpecs(mass=2731, wheelbase=3.302, steerRatio=17.3, centerToFrontRatio=0.49),
|
||||
sp_flags=GMFlagsSP.NON_ACC,
|
||||
)
|
||||
CADILLAC_CT6_NON_ACC_1ST_GEN = GMPlatformConfig(
|
||||
[GMCarDocs("Cadillac CT6 Non-ACC 2017-18")],
|
||||
CADILLAC_CT6_NON_ACC_1ST_GEN = GMNonSccPlatformConfig(
|
||||
[GMNonAccCarDocs("Cadillac CT6 Non-ACC 2017-18")],
|
||||
CarSpecs(mass=2358, wheelbase=3.11, steerRatio=17.7, centerToFrontRatio=0.4),
|
||||
sp_flags=GMFlagsSP.NON_ACC,
|
||||
)
|
||||
CHEVROLET_TRAILBLAZER_NON_ACC_2ND_GEN = GMPlatformConfig(
|
||||
[GMCarDocs("Chevrolet Trailblazer Non-ACC 2021-22")],
|
||||
CHEVROLET_TRAILBLAZER_NON_ACC_2ND_GEN = GMNonSccPlatformConfig(
|
||||
[GMNonAccCarDocs("Chevrolet Trailblazer Non-ACC 2021-22")],
|
||||
CHEVROLET_TRAILBLAZER.specs,
|
||||
sp_flags=GMFlagsSP.NON_ACC,
|
||||
)
|
||||
CHEVROLET_MALIBU_NON_ACC_9TH_GEN = GMPlatformConfig(
|
||||
[GMCarDocs("Chevrolet Malibu Non-ACC 2016-23")],
|
||||
CHEVROLET_MALIBU_NON_ACC_9TH_GEN = GMNonSccPlatformConfig(
|
||||
[GMNonAccCarDocs("Chevrolet Malibu Non-ACC 2016-23")],
|
||||
CarSpecs(mass=1450, wheelbase=2.8, steerRatio=15.8, centerToFrontRatio=0.4),
|
||||
sp_flags=GMFlagsSP.NON_ACC,
|
||||
)
|
||||
CADILLAC_XT5_NON_ACC_1ST_GEN = GMPlatformConfig(
|
||||
[GMCarDocs("Cadillac XT5 Non-ACC 2018")],
|
||||
CADILLAC_XT5_NON_ACC_1ST_GEN = GMNonSccPlatformConfig(
|
||||
[GMNonAccCarDocs("Cadillac XT5 Non-ACC 2018")],
|
||||
CarSpecs(mass=1810, wheelbase=2.86, steerRatio=16.34, centerToFrontRatio=0.5),
|
||||
sp_flags=GMFlagsSP.NON_ACC,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -51,6 +51,8 @@ class CarState(CarStateBase, CarStateExt):
|
||||
# When available we use cp.vl["CAR_SPEED"]["ROUGH_CAR_SPEED_2"] to populate vEgoCluster
|
||||
# However, on cars without a digital speedometer this is not always present (HRV, FIT, CRV 2016, ILX and RDX)
|
||||
self.dash_speed_seen = False
|
||||
self.is_metric = False
|
||||
self.v_cruise_factor = 1.
|
||||
|
||||
def update(self, can_parsers) -> tuple[structs.CarState, structs.CarStateSP]:
|
||||
cp = can_parsers[Bus.pt]
|
||||
@@ -72,7 +74,8 @@ class CarState(CarStateBase, CarStateExt):
|
||||
self.cruise_buttons = cp.vl["SCM_BUTTONS"]["CRUISE_BUTTONS"]
|
||||
|
||||
# used for car hud message
|
||||
self.is_metric = not cp.vl["CAR_SPEED"]["IMPERIAL_UNIT"]
|
||||
# TODO: find CAR_SPEED for HONDA_ODYSSEY_TWN or use ACC_HUD w/ detection
|
||||
self.is_metric = self.CP.carFingerprint in (CAR.HONDA_ODYSSEY_TWN,) or not cp.vl["CAR_SPEED"]["IMPERIAL_UNIT"]
|
||||
self.v_cruise_factor = CV.MPH_TO_MS if self.dynamic_v_cruise_units and not self.is_metric else CV.KPH_TO_MS
|
||||
|
||||
# ******************* parse out can *******************
|
||||
@@ -131,10 +134,11 @@ class CarState(CarStateBase, CarStateExt):
|
||||
|
||||
ret.espDisabled = cp.vl["VSA_STATUS"]["ESP_DISABLED"] != 0
|
||||
|
||||
self.dash_speed_seen = self.dash_speed_seen or cp.vl["CAR_SPEED"]["ROUGH_CAR_SPEED_2"] > 1e-3
|
||||
if self.dash_speed_seen:
|
||||
conversion = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS
|
||||
ret.vEgoCluster = cp.vl["CAR_SPEED"]["ROUGH_CAR_SPEED_2"] * conversion
|
||||
if self.CP.carFingerprint not in (CAR.HONDA_ODYSSEY_TWN,):
|
||||
self.dash_speed_seen = self.dash_speed_seen or cp.vl["CAR_SPEED"]["ROUGH_CAR_SPEED_2"] > 1e-3
|
||||
if self.dash_speed_seen:
|
||||
conversion = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS
|
||||
ret.vEgoCluster = cp.vl["CAR_SPEED"]["ROUGH_CAR_SPEED_2"] * conversion
|
||||
|
||||
ret.steeringAngleDeg = cp.vl["STEERING_SENSORS"]["STEER_ANGLE"]
|
||||
ret.steeringRateDeg = cp.vl["STEERING_SENSORS"]["STEER_ANGLE_RATE"]
|
||||
|
||||
@@ -223,10 +223,12 @@ FW_VERSIONS = {
|
||||
b'57114-TBG-A340\x00\x00',
|
||||
b'57114-TBG-A350\x00\x00',
|
||||
b'57114-TGG-A340\x00\x00',
|
||||
b'57114-TGG-C120\x00\x00',
|
||||
b'57114-TGG-C320\x00\x00',
|
||||
b'57114-TGG-G320\x00\x00',
|
||||
b'57114-TGG-L320\x00\x00',
|
||||
b'57114-TGG-L330\x00\x00',
|
||||
b'57114-TGH-A130\x00\x00',
|
||||
b'57114-TGH-L130\x00\x00',
|
||||
b'57114-TGJ-Q330\x00\x00',
|
||||
b'57114-TGK-T320\x00\x00',
|
||||
@@ -241,6 +243,7 @@ FW_VERSIONS = {
|
||||
b'39990-TGG-A020\x00\x00',
|
||||
b'39990-TGG-A120\x00\x00',
|
||||
b'39990-TGG-J510\x00\x00',
|
||||
b'39990-TGH-J020\x00\x00',
|
||||
b'39990-TGH-J530\x00\x00',
|
||||
b'39990-TGL-E130\x00\x00',
|
||||
b'39990-TGN-E120\x00\x00',
|
||||
@@ -257,6 +260,7 @@ FW_VERSIONS = {
|
||||
b'77959-TGG-J320\x00\x00',
|
||||
b'77959-TGG-Q810\x00\x00',
|
||||
b'77959-TGG-Z820\x00\x00',
|
||||
b'77959-TGH-E220\x00\x00',
|
||||
b'77959-TGH-J110\x00\x00',
|
||||
],
|
||||
(Ecu.fwdRadar, 0x18dab0f1, None): [
|
||||
@@ -269,6 +273,7 @@ FW_VERSIONS = {
|
||||
b'36802-TGG-A130\x00\x00',
|
||||
b'36802-TGG-G040\x00\x00',
|
||||
b'36802-TGG-G130\x00\x00',
|
||||
b'36802-TGH-A030\x00\x00',
|
||||
b'36802-TGH-A140\x00\x00',
|
||||
b'36802-TGK-Q030\x00\x00',
|
||||
b'36802-TGK-Q120\x00\x00',
|
||||
@@ -285,6 +290,7 @@ FW_VERSIONS = {
|
||||
b'36161-TGG-G070\x00\x00',
|
||||
b'36161-TGG-G130\x00\x00',
|
||||
b'36161-TGG-G140\x00\x00',
|
||||
b'36161-TGH-A020\x00\x00',
|
||||
b'36161-TGH-A140\x00\x00',
|
||||
b'36161-TGK-Q040\x00\x00',
|
||||
b'36161-TGK-Q120\x00\x00',
|
||||
@@ -580,6 +586,17 @@ FW_VERSIONS = {
|
||||
b'54008-THR-A020\x00\x00',
|
||||
],
|
||||
},
|
||||
CAR.HONDA_ODYSSEY_TWN: {
|
||||
(Ecu.eps, 0x18da30f1, None): [
|
||||
b'39990-T6A-J210\x00\x00',
|
||||
],
|
||||
(Ecu.srs, 0x18da53f1, None): [
|
||||
b'77959-T6A-P110\x00\x00',
|
||||
],
|
||||
(Ecu.fwdRadar, 0x18dab0f1, None): [
|
||||
b'36161-T6A-P040\x00\x00',
|
||||
],
|
||||
},
|
||||
CAR.HONDA_ODYSSEY_5G_MMR: {
|
||||
(Ecu.vsa, 0x18da28f1, None): [
|
||||
b'57114-THR-A240\x00\x00',
|
||||
@@ -858,6 +875,7 @@ FW_VERSIONS = {
|
||||
b'77959-3V0-A910\x00\x00',
|
||||
],
|
||||
(Ecu.fwdRadar, 0x18dab0f1, None): [
|
||||
b'8S102-3M1-T050\x00\x00',
|
||||
b'8S102-3M3-T050\x00\x00',
|
||||
b'8S102-3M6-P030\x00\x00',
|
||||
b'8S102-3M6-PA20\x00\x00',
|
||||
@@ -1070,6 +1088,14 @@ FW_VERSIONS = {
|
||||
b'36161-TGV-A030\x00\x00',
|
||||
],
|
||||
},
|
||||
CAR.ACURA_TLX_2G_MMR: {
|
||||
(Ecu.fwdRadar, 0x18dab0f1, None): [
|
||||
b'8S302-TGV-A030\x00\x00',
|
||||
],
|
||||
(Ecu.fwdCamera, 0x18dab5f1, None): [
|
||||
b'8S102-TGV-A030\x00\x00',
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
FW_VERSIONS = merge_fw_versions(FW_VERSIONS, FW_VERSIONS_EXT)
|
||||
|
||||
@@ -167,6 +167,10 @@ class CarInterface(CarInterfaceBase):
|
||||
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.28], [0.08]]
|
||||
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
|
||||
|
||||
elif candidate == CAR.HONDA_ODYSSEY_TWN:
|
||||
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.28], [0.08]]
|
||||
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 32767], [0, 32767]] # TODO: determine if there is a dead zone at the top end
|
||||
|
||||
elif candidate == CAR.HONDA_PILOT:
|
||||
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
|
||||
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.38], [0.11]]
|
||||
@@ -195,6 +199,11 @@ class CarInterface(CarInterfaceBase):
|
||||
# When using stock ACC, the radar intercepts and filters steering commands the EPS would otherwise accept
|
||||
ret.minSteerSpeed = 70. * CV.KPH_TO_MS
|
||||
|
||||
elif candidate == CAR.ACURA_TLX_2G_MMR:
|
||||
ret.steerActuatorDelay = 0.15
|
||||
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 3840], [0, 3840]]
|
||||
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
|
||||
|
||||
# TODO-SP: remove when https://github.com/commaai/opendbc/pull/2687 is merged
|
||||
elif candidate == CAR.HONDA_CLARITY:
|
||||
pass
|
||||
@@ -205,7 +214,7 @@ class CarInterface(CarInterfaceBase):
|
||||
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
|
||||
|
||||
# These cars use alternate user brake msg (0x1BE)
|
||||
if 0x1BE in fingerprint[CAN.pt] and candidate in (CAR.HONDA_ACCORD, CAR.HONDA_HRV_3G, *HONDA_BOSCH_CANFD):
|
||||
if 0x1BE in fingerprint[CAN.pt] and candidate in (CAR.HONDA_ACCORD, CAR.HONDA_HRV_3G, CAR.ACURA_RDX_3G, *HONDA_BOSCH_CANFD):
|
||||
ret.flags |= HondaFlags.BOSCH_ALT_BRAKE.value
|
||||
|
||||
if ret.flags & HondaFlags.BOSCH_ALT_BRAKE:
|
||||
@@ -223,7 +232,12 @@ class CarInterface(CarInterfaceBase):
|
||||
# to a negative value, so it won't matter. Otherwise, add 0.5 mph margin to not
|
||||
# conflict with PCM acc
|
||||
ret.autoResumeSng = candidate in (HONDA_BOSCH | {CAR.HONDA_CIVIC})
|
||||
ret.minEnableSpeed = -1. if ret.autoResumeSng else 25.51 * CV.MPH_TO_MS
|
||||
if ret.autoResumeSng:
|
||||
ret.minEnableSpeed = -1.
|
||||
elif candidate == CAR.HONDA_ODYSSEY_TWN:
|
||||
ret.minEnableSpeed = 19. * CV.MPH_TO_MS
|
||||
else:
|
||||
ret.minEnableSpeed = 25.51 * CV.MPH_TO_MS
|
||||
|
||||
ret.steerLimitTimer = 0.8
|
||||
ret.radarDelay = 0.1
|
||||
|
||||
@@ -3,7 +3,7 @@ from enum import Enum, IntFlag
|
||||
|
||||
from opendbc.car import Bus, CarSpecs, DbcDict, PlatformConfig, Platforms, structs, uds
|
||||
from opendbc.car.common.conversions import Conversions as CV
|
||||
from opendbc.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column
|
||||
from opendbc.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column, SupportType
|
||||
from opendbc.car.fw_query_definitions import FwQueryConfig, Request, StdQueries, p16
|
||||
|
||||
Ecu = structs.CarParams.Ecu
|
||||
@@ -114,6 +114,8 @@ class HondaCarDocs(CarDocs):
|
||||
if CP.carFingerprint in (CAR.HONDA_CLARITY,):
|
||||
self.car_parts = CarParts.common([CarHarness.honda_clarity])
|
||||
self.car_parts.custom_parts_url = "https://shop.retropilot.org/product/honda-clarity-proxy-board-kit"
|
||||
self.support_type: SupportType = SupportType.COMMUNITY
|
||||
self.support_link: str = "community"
|
||||
|
||||
|
||||
class Footnote(Enum):
|
||||
@@ -189,6 +191,7 @@ class CAR(Platforms):
|
||||
],
|
||||
CarSpecs(mass=1326, wheelbase=2.7, steerRatio=15.38, centerToFrontRatio=0.4), # steerRatio: 10.93 is end-to-end spec
|
||||
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated'},
|
||||
flags=HondaFlags.ALLOW_MANUAL_TRANS,
|
||||
)
|
||||
HONDA_CIVIC_BOSCH_DIESEL = HondaBoschPlatformConfig(
|
||||
[], # don't show in docs
|
||||
@@ -281,6 +284,11 @@ class CAR(Platforms):
|
||||
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated'},
|
||||
flags=HondaFlags.BOSCH_ALT_RADAR,
|
||||
)
|
||||
# mid-model refresh
|
||||
ACURA_TLX_2G_MMR = HondaBoschCANFDPlatformConfig(
|
||||
[HondaCarDocs("Acura TLX 2025", "All")],
|
||||
CarSpecs(mass=3990 * CV.LB_TO_KG, wheelbase=2.87, centerToFrontRatio=0.43, steerRatio=13.7),
|
||||
)
|
||||
|
||||
# Nidec Cars
|
||||
ACURA_ILX = HondaNidecPlatformConfig(
|
||||
@@ -328,6 +336,12 @@ class CAR(Platforms):
|
||||
radar_dbc_dict('honda_odyssey_exl_2018_generated'),
|
||||
flags=HondaFlags.NIDEC_ALT_PCM_ACCEL | HondaFlags.HAS_ALL_DOOR_STATES,
|
||||
)
|
||||
HONDA_ODYSSEY_TWN = HondaNidecPlatformConfig(
|
||||
[HondaCarDocs("Honda Odyssey (Taiwan) 2018-19")],
|
||||
CarSpecs(mass=1865, wheelbase=2.9, steerRatio=14.35, centerToFrontRatio=0.44, tireStiffnessFactor=0.82),
|
||||
radar_dbc_dict('honda_odyssey_twn_2018_generated'),
|
||||
flags=HondaFlags.NIDEC_ALT_SCM_MESSAGES,
|
||||
)
|
||||
ACURA_RDX = HondaNidecPlatformConfig(
|
||||
[HondaCarDocs("Acura RDX 2016-18", "AcuraWatch Plus or Advance Package", min_steer_speed=12. * CV.MPH_TO_MS)],
|
||||
CarSpecs(mass=3925 * CV.LB_TO_KG, wheelbase=2.68, steerRatio=15.0, centerToFrontRatio=0.38, tireStiffnessFactor=0.444), # as spec
|
||||
|
||||
@@ -701,6 +701,7 @@ FW_VERSIONS = {
|
||||
b'\xf1\x00OSP MDPS C 1.00 1.02 56310-K4271 4OEPC102',
|
||||
b'\xf1\x00OSP MDPS C 1.00 1.02 56310/K4271 4OEPC102',
|
||||
b'\xf1\x00OSP MDPS C 1.00 1.02 56310/K4970 4OEPC102',
|
||||
b'\xf1\x00OSP MDPS C 1.00 1.02 56310/K4971 4OEPC102',
|
||||
b'\xf1\x00OSP MDPS C 1.00 1.02 56310K4260\x00 4OEPC102',
|
||||
b'\xf1\x00OSP MDPS C 1.00 1.02 56310K4261\x00 4OEPC102',
|
||||
b'\xf1\x00OSP MDPS C 1.00 1.02 56310K4971\x00 4OEPC102',
|
||||
@@ -1087,12 +1088,14 @@ FW_VERSIONS = {
|
||||
b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N9260 14Y',
|
||||
b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.01 99211-N9100 14A',
|
||||
b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.01 99211-N9240 14T',
|
||||
b'\xf1\x00NX4 FR_CMR AT EUR LHD 1.00 1.00 99211-N9240 14Q',
|
||||
],
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00NX4__ 1.00 1.00 99110-N9100 ',
|
||||
b'\xf1\x00NX4__ 1.00 1.01 99110-N9000 ',
|
||||
b'\xf1\x00NX4__ 1.00 1.02 99110-N9000 ',
|
||||
b'\xf1\x00NX4__ 1.01 1.00 99110-N9100 ',
|
||||
b'\xf1\x00NX4__ 1.01 1.02 99110-N9000 ',
|
||||
],
|
||||
},
|
||||
CAR.HYUNDAI_SANTA_CRUZ_1ST_GEN: {
|
||||
|
||||
@@ -5,7 +5,7 @@ from enum import IntFlag
|
||||
from opendbc.car import Bus, CarSpecs, DbcDict, PlatformConfig, Platforms, uds
|
||||
from opendbc.car.common.conversions import Conversions as CV
|
||||
from opendbc.car.structs import CarParams
|
||||
from opendbc.car.docs_definitions import CarHarness, CarDocs, CarParts
|
||||
from opendbc.car.docs_definitions import CarHarness, CarDocs, CarParts, SupportType
|
||||
from opendbc.car.fw_query_definitions import FwQueryConfig, Request, p16
|
||||
|
||||
from opendbc.sunnypilot.car.hyundai.values import HyundaiFlagsSP
|
||||
@@ -134,6 +134,13 @@ class HyundaiCarDocs(CarDocs):
|
||||
package: str = "Smart Cruise Control (SCC)"
|
||||
|
||||
|
||||
@dataclass
|
||||
class HyundaiNonSccCarDocs(CarDocs):
|
||||
package: str = "No Smart Cruise Control (Non-SCC)"
|
||||
support_type: SupportType = SupportType.COMMUNITY
|
||||
support_link: str = "community"
|
||||
|
||||
|
||||
@dataclass
|
||||
class HyundaiPlatformConfig(PlatformConfig):
|
||||
dbc_dict: DbcDict = field(default_factory=lambda: {Bus.pt: "hyundai_kia_generic"})
|
||||
@@ -146,6 +153,17 @@ class HyundaiPlatformConfig(PlatformConfig):
|
||||
self.specs = self.specs.override(minSteerSpeed=32 * CV.MPH_TO_MS)
|
||||
|
||||
|
||||
@dataclass
|
||||
class HyundaiNonSccPlatformConfig(PlatformConfig):
|
||||
dbc_dict: DbcDict = field(default_factory=lambda: {Bus.pt: "hyundai_kia_generic"})
|
||||
|
||||
def init(self):
|
||||
self.sp_flags |= HyundaiFlagsSP.NON_SCC
|
||||
|
||||
if self.flags & HyundaiFlags.MIN_STEER_32_MPH:
|
||||
self.specs = self.specs.override(minSteerSpeed=32 * CV.MPH_TO_MS)
|
||||
|
||||
|
||||
@dataclass
|
||||
class HyundaiCanFDPlatformConfig(PlatformConfig):
|
||||
dbc_dict: DbcDict = field(default_factory=lambda: {Bus.pt: "hyundai_canfd_generated"})
|
||||
@@ -589,57 +607,50 @@ class CAR(Platforms):
|
||||
)
|
||||
|
||||
# port extensions
|
||||
HYUNDAI_BAYON_1ST_GEN_NON_SCC = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Hyundai Bayon Non-SCC 2021", "No Smart Cruise Control (Non-SCC)", car_parts=CarParts.common([CarHarness.hyundai_n]))],
|
||||
HYUNDAI_BAYON_1ST_GEN_NON_SCC = HyundaiNonSccPlatformConfig(
|
||||
[HyundaiNonSccCarDocs("Hyundai Bayon Non-SCC 2021", car_parts=CarParts.common([CarHarness.hyundai_n]))],
|
||||
CarSpecs(mass=1150, wheelbase=2.58, steerRatio=13.27 * 1.15),
|
||||
flags=HyundaiFlags.CHECKSUM_CRC8,
|
||||
sp_flags=HyundaiFlagsSP.NON_SCC,
|
||||
)
|
||||
HYUNDAI_ELANTRA_2022_NON_SCC = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Hyundai Elantra Non-SCC 2022", "No Smart Cruise Control (Non-SCC)", car_parts=CarParts.common([CarHarness.hyundai_k]))],
|
||||
HYUNDAI_ELANTRA_2022_NON_SCC = HyundaiNonSccPlatformConfig(
|
||||
[HyundaiNonSccCarDocs("Hyundai Elantra Non-SCC 2022", car_parts=CarParts.common([CarHarness.hyundai_k]))],
|
||||
HYUNDAI_ELANTRA_2021.specs,
|
||||
flags=HyundaiFlags.CHECKSUM_CRC8,
|
||||
sp_flags=HyundaiFlagsSP.NON_SCC,
|
||||
)
|
||||
HYUNDAI_KONA_NON_SCC = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Hyundai Kona Non-SCC 2019", "No Smart Cruise Control (Non-SCC)", car_parts=CarParts.common([CarHarness.hyundai_b]))],
|
||||
HYUNDAI_KONA_NON_SCC = HyundaiNonSccPlatformConfig(
|
||||
[HyundaiNonSccCarDocs("Hyundai Kona Non-SCC 2019", car_parts=CarParts.common([CarHarness.hyundai_b]))],
|
||||
HYUNDAI_KONA.specs,
|
||||
flags=HyundaiFlags.ALT_LIMITS,
|
||||
sp_flags=HyundaiFlagsSP.NON_SCC,
|
||||
)
|
||||
HYUNDAI_KONA_EV_NON_SCC = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Hyundai Kona Electric Non-SCC 2019", "No Smart Cruise Control (Non-SCC)", car_parts=CarParts.common([CarHarness.hyundai_g]))],
|
||||
HYUNDAI_KONA_EV_NON_SCC = HyundaiNonSccPlatformConfig(
|
||||
[HyundaiNonSccCarDocs("Hyundai Kona Electric Non-SCC 2019", car_parts=CarParts.common([CarHarness.hyundai_g]))],
|
||||
HYUNDAI_KONA_EV.specs,
|
||||
flags=HyundaiFlags.EV | HyundaiFlags.ALT_LIMITS,
|
||||
sp_flags=HyundaiFlagsSP.NON_SCC,
|
||||
)
|
||||
KIA_CEED_PHEV_2022_NON_SCC = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Kia Ceed Plug-in Hybrid Non-SCC 2022", "No Smart Cruise Control (Non-SCC)", car_parts=CarParts.common([CarHarness.hyundai_i]))],
|
||||
KIA_CEED_PHEV_2022_NON_SCC = HyundaiNonSccPlatformConfig(
|
||||
[HyundaiNonSccCarDocs("Kia Ceed Plug-in Hybrid Non-SCC 2022", car_parts=CarParts.common([CarHarness.hyundai_i]))],
|
||||
CarSpecs(mass=1650, wheelbase=2.65, steerRatio=13.75, tireStiffnessFactor=0.5),
|
||||
flags=HyundaiFlags.HYBRID,
|
||||
sp_flags=HyundaiFlagsSP.NON_SCC,
|
||||
)
|
||||
KIA_FORTE_2019_NON_SCC = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Kia Forte Non-SCC 2019", "No Smart Cruise Control (Non-SCC)", car_parts=CarParts.common([CarHarness.hyundai_g]))],
|
||||
KIA_FORTE_2019_NON_SCC = HyundaiNonSccPlatformConfig(
|
||||
[HyundaiNonSccCarDocs("Kia Forte Non-SCC 2019", car_parts=CarParts.common([CarHarness.hyundai_g]))],
|
||||
KIA_FORTE.specs,
|
||||
sp_flags=HyundaiFlagsSP.NON_SCC | HyundaiFlagsSP.NON_SCC_NO_FCA,
|
||||
sp_flags=HyundaiFlagsSP.NON_SCC_NO_FCA,
|
||||
)
|
||||
KIA_FORTE_2021_NON_SCC = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Kia Forte Non-SCC 2021", "No Smart Cruise Control (Non-SCC)", car_parts=CarParts.common([CarHarness.hyundai_g]))],
|
||||
KIA_FORTE_2021_NON_SCC = HyundaiNonSccPlatformConfig(
|
||||
[HyundaiNonSccCarDocs("Kia Forte Non-SCC 2021", car_parts=CarParts.common([CarHarness.hyundai_g]))],
|
||||
KIA_FORTE.specs,
|
||||
sp_flags=HyundaiFlagsSP.NON_SCC,
|
||||
)
|
||||
KIA_SELTOS_2023_NON_SCC = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Kia Seltos Non-SCC 2023-24", "No Smart Cruise Control (Non-SCC)", car_parts=CarParts.common([CarHarness.hyundai_l]))],
|
||||
KIA_SELTOS_2023_NON_SCC = HyundaiNonSccPlatformConfig(
|
||||
[HyundaiNonSccCarDocs("Kia Seltos Non-SCC 2023-24", car_parts=CarParts.common([CarHarness.hyundai_l]))],
|
||||
KIA_SELTOS.specs,
|
||||
flags=HyundaiFlags.CHECKSUM_CRC8,
|
||||
sp_flags=HyundaiFlagsSP.NON_SCC,
|
||||
)
|
||||
GENESIS_G70_2021_NON_SCC = HyundaiPlatformConfig(
|
||||
[HyundaiCarDocs("Genesis G70 Non-SCC 2021", "No Smart Cruise Control (Non-SCC)", car_parts=CarParts.common([CarHarness.hyundai_f]))],
|
||||
GENESIS_G70_2021_NON_SCC = HyundaiNonSccPlatformConfig(
|
||||
[HyundaiNonSccCarDocs("Genesis G70 Non-SCC 2021", car_parts=CarParts.common([CarHarness.hyundai_f]))],
|
||||
GENESIS_G70_2020.specs,
|
||||
flags=HyundaiFlags.CHECKSUM_CRC8,
|
||||
sp_flags=HyundaiFlagsSP.NON_SCC | HyundaiFlagsSP.NON_SCC_RADAR_FCA,
|
||||
sp_flags=HyundaiFlagsSP.NON_SCC_RADAR_FCA,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ from opendbc.car import structs, rate_limit, DT_CTRL, ACCELERATION_DUE_TO_GRAVIT
|
||||
from opendbc.car.vehicle_model import VehicleModel
|
||||
from typing import Tuple
|
||||
|
||||
FRICTION_THRESHOLD = 0.3
|
||||
FRICTION_THRESHOLD = 0.2
|
||||
|
||||
# ISO 11270
|
||||
ISO_LATERAL_ACCEL = 3.0 # m/s^2
|
||||
|
||||
@@ -4,15 +4,12 @@ from opendbc.car.common.conversions import Conversions as CV
|
||||
from opendbc.car.interfaces import CarStateBase
|
||||
from opendbc.car.mazda.values import DBC, LKAS_LIMITS
|
||||
|
||||
from opendbc.sunnypilot.car.mazda.carstate_ext import CarStateExt
|
||||
|
||||
ButtonType = structs.CarState.ButtonEvent.Type
|
||||
|
||||
|
||||
class CarState(CarStateBase, CarStateExt):
|
||||
class CarState(CarStateBase):
|
||||
def __init__(self, CP, CP_SP):
|
||||
CarStateBase.__init__(self, CP, CP_SP)
|
||||
CarStateExt.__init__(self, CP, CP_SP)
|
||||
super().__init__(CP, CP_SP)
|
||||
|
||||
can_define = CANDefine(DBC[CP.carFingerprint][Bus.pt])
|
||||
self.shifter_values = can_define.dv["GEAR"]["GEAR"]
|
||||
@@ -22,6 +19,8 @@ class CarState(CarStateBase, CarStateExt):
|
||||
self.lkas_allowed_speed = False
|
||||
|
||||
self.distance_button = 0
|
||||
self.accel_button = 0
|
||||
self.decel_button = 0
|
||||
|
||||
def update(self, can_parsers) -> tuple[structs.CarState, structs.CarStateSP]:
|
||||
cp = can_parsers[Bus.pt]
|
||||
@@ -30,9 +29,6 @@ class CarState(CarStateBase, CarStateExt):
|
||||
ret = structs.CarState()
|
||||
ret_sp = structs.CarStateSP()
|
||||
|
||||
prev_distance_button = self.distance_button
|
||||
self.distance_button = cp.vl["CRZ_BTNS"]["DISTANCE_LESS"]
|
||||
|
||||
self.parse_wheel_speeds(ret,
|
||||
cp.vl["WHEEL_SPEEDS"]["FL"],
|
||||
cp.vl["WHEEL_SPEEDS"]["FR"],
|
||||
@@ -116,12 +112,18 @@ class CarState(CarStateBase, CarStateExt):
|
||||
self.cam_laneinfo = cp_cam.vl["CAM_LANEINFO"]
|
||||
ret.steerFaultPermanent = cp_cam.vl["CAM_LKAS"]["ERR_BIT_1"] == 1
|
||||
|
||||
CarStateExt.update(self, ret, ret_sp, can_parsers)
|
||||
# cruise control button events: distance, inc, and dec
|
||||
prev_distance_button = self.distance_button
|
||||
prev_accel_button = self.accel_button
|
||||
prev_decel_button = self.decel_button
|
||||
self.distance_button = cp.vl["CRZ_BTNS"]["DISTANCE_LESS"]
|
||||
self.accel_button = cp.vl["CRZ_BTNS"]["RES"]
|
||||
self.decel_button = cp.vl["CRZ_BTNS"]["SET_M"]
|
||||
|
||||
# TODO: add button types for inc and dec
|
||||
ret.buttonEvents = [
|
||||
*create_button_events(self.distance_button, prev_distance_button, {1: ButtonType.gapAdjustCruise}),
|
||||
*self.button_events,
|
||||
*create_button_events(self.accel_button, prev_accel_button, {1: ButtonType.accelCruise}),
|
||||
*create_button_events(self.decel_button, prev_decel_button, {1: ButtonType.decelCruise}),
|
||||
]
|
||||
|
||||
return ret, ret_sp
|
||||
|
||||
@@ -16,6 +16,7 @@ class CarInterface(CarInterfaceBase):
|
||||
ret.brand = "nissan"
|
||||
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.nissan)]
|
||||
ret.autoResumeSng = False
|
||||
ret.steerAtStandstill = True
|
||||
|
||||
ret.steerLimitTimer = 1.0
|
||||
|
||||
|
||||
@@ -66,11 +66,19 @@ class CarState(CarStateBase, MadsCarState, SnGCarState):
|
||||
can_gear = int(cp_transmission.vl["Transmission"]["Gear"])
|
||||
ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(can_gear, None))
|
||||
|
||||
ret.steeringAngleDeg = cp.vl["Steering_Torque"]["Steering_Angle"]
|
||||
if not (self.CP.flags & SubaruFlags.LKAS_ANGLE):
|
||||
ret.steeringAngleDeg = cp.vl["Steering_Torque"]["Steering_Angle"]
|
||||
steering_updated = len(cp.vl_all["Steering_Torque"]["Steering_Angle"]) > 0
|
||||
else:
|
||||
# Steering_Torque->Steering_Angle exists on SUBARU_FORESTER_2022, SUBARU_OUTBACK_2023, SUBARU_ASCENT_2023 where
|
||||
# it is identical to Steering_2's signal. However, it is always zero on newer LKAS_ANGLE cars
|
||||
# such as 2024+ Crosstrek, 2023+ Ascent, etc. Use a universal signal for LKAS_ANGLE cars.
|
||||
ret.steeringAngleDeg = cp.vl["Steering_2"]["Steering_Angle"]
|
||||
steering_updated = len(cp.vl_all["Steering_2"]["Steering_Angle"]) > 0
|
||||
|
||||
if not (self.CP.flags & SubaruFlags.PREGLOBAL):
|
||||
# ideally we get this from the car, but unclear if it exists. diagnostic software doesn't even have it
|
||||
ret.steeringRateDeg = self.angle_rate_calulator.update(ret.steeringAngleDeg, cp.vl["Steering_Torque"]["COUNTER"])
|
||||
ret.steeringRateDeg = self.angle_rate_calulator.update(ret.steeringAngleDeg, steering_updated)
|
||||
|
||||
ret.steeringTorque = cp.vl["Steering_Torque"]["Steer_Torque_Sensor"]
|
||||
ret.steeringTorqueEps = cp.vl["Steering_Torque"]["Steer_Torque_Output"]
|
||||
@@ -79,8 +87,16 @@ class CarState(CarStateBase, MadsCarState, SnGCarState):
|
||||
ret.steeringPressed = abs(ret.steeringTorque) > steer_threshold
|
||||
|
||||
cp_cruise = cp_alt if self.CP.flags & SubaruFlags.GLOBAL_GEN2 else cp
|
||||
if self.CP.flags & SubaruFlags.HYBRID:
|
||||
ret.cruiseState.enabled = cp_cam.vl["ES_DashStatus"]['Cruise_Activated'] != 0
|
||||
cp_es_brake = cp_alt if self.CP.flags & SubaruFlags.GLOBAL_GEN2 else cp_cam
|
||||
|
||||
if self.CP.flags & (SubaruFlags.HYBRID | SubaruFlags.LKAS_ANGLE):
|
||||
# ES_DashStatus->Cruise_Activated_Dash is likely intended for the dash display only, as it falls
|
||||
# during user gas override and at standstill. ES_Status is missing on hybrid, so we use ES_Brake instead
|
||||
|
||||
# TODO: ES_Brake->Cruise_Activated has been seen staying high when Crosstrek 2025 angle LKAS user pressed
|
||||
# brake while engaged at a stop. ES_Status and ES_DashStatus->Signal7 correctly fell, but is either missing or
|
||||
# always zero on hybrids. Probably need to split angle & hybrid. 0x27 and 0x225 on hybrids may work for them.
|
||||
ret.cruiseState.enabled = cp_es_brake.vl["ES_Brake"]['Cruise_Activated'] != 0
|
||||
ret.cruiseState.available = cp_cam.vl["ES_DashStatus"]['Cruise_On'] != 0
|
||||
else:
|
||||
ret.cruiseState.enabled = cp_cruise.vl["CruiseControl"]["Cruise_Activated"] != 0
|
||||
@@ -109,9 +125,7 @@ class CarState(CarStateBase, MadsCarState, SnGCarState):
|
||||
(cp_cam.vl["ES_LKAS_State"]["LKAS_Alert"] == 2)
|
||||
|
||||
self.es_lkas_state_msg = copy.copy(cp_cam.vl["ES_LKAS_State"])
|
||||
cp_es_brake = cp_alt if self.CP.flags & SubaruFlags.GLOBAL_GEN2 else cp_cam
|
||||
self.es_brake_msg = copy.copy(cp_es_brake.vl["ES_Brake"])
|
||||
cp_es_status = cp_alt if self.CP.flags & SubaruFlags.GLOBAL_GEN2 else cp_cam
|
||||
|
||||
# TODO: Hybrid cars don't have ES_Distance, need a replacement
|
||||
if not (self.CP.flags & SubaruFlags.HYBRID):
|
||||
@@ -119,7 +133,7 @@ class CarState(CarStateBase, MadsCarState, SnGCarState):
|
||||
ret.stockAeb = (cp_es_distance.vl["ES_Brake"]["AEB_Status"] == 8) and \
|
||||
(cp_es_distance.vl["ES_Brake"]["Brake_Pressure"] != 0)
|
||||
|
||||
self.es_status_msg = copy.copy(cp_es_status.vl["ES_Status"])
|
||||
self.es_status_msg = copy.copy(cp_es_brake.vl["ES_Status"])
|
||||
self.cruise_control_msg = copy.copy(cp_cruise.vl["CruiseControl"])
|
||||
|
||||
if not (self.CP.flags & SubaruFlags.HYBRID):
|
||||
|
||||
@@ -146,6 +146,7 @@ FW_VERSIONS = {
|
||||
b'\xc5!ap\x07',
|
||||
b'\xc5!ar\x07',
|
||||
b'\xc5!as\x07',
|
||||
b'\xc5!au\x07',
|
||||
b'\xc5!dr\x07',
|
||||
b'\xc5!ds\x07',
|
||||
b'\xca\x01b0\x07',
|
||||
|
||||
@@ -37,12 +37,13 @@ class CarInterface(CarInterfaceBase):
|
||||
ret.steerLimitTimer = 0.4
|
||||
ret.steerActuatorDelay = 0.1
|
||||
|
||||
if ret.flags & SubaruFlags.LKAS_ANGLE:
|
||||
ret.steerControlType = structs.CarParams.SteerControlType.angle
|
||||
else:
|
||||
if not (ret.flags & SubaruFlags.LKAS_ANGLE):
|
||||
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
|
||||
|
||||
if candidate in (CAR.SUBARU_ASCENT, CAR.SUBARU_ASCENT_2023):
|
||||
if ret.flags & SubaruFlags.LKAS_ANGLE:
|
||||
ret.steerControlType = structs.CarParams.SteerControlType.angle
|
||||
|
||||
elif candidate == CAR.SUBARU_ASCENT:
|
||||
ret.steerActuatorDelay = 0.3 # end-to-end angle controller
|
||||
ret.lateralTuning.init('pid')
|
||||
ret.lateralTuning.pid.kf = 0.00003
|
||||
@@ -65,13 +66,13 @@ class CarInterface(CarInterfaceBase):
|
||||
elif candidate == CAR.SUBARU_CROSSTREK_HYBRID:
|
||||
ret.steerActuatorDelay = 0.1
|
||||
|
||||
elif candidate in (CAR.SUBARU_FORESTER, CAR.SUBARU_FORESTER_2022, CAR.SUBARU_FORESTER_HYBRID):
|
||||
elif candidate in (CAR.SUBARU_FORESTER, CAR.SUBARU_FORESTER_HYBRID):
|
||||
ret.lateralTuning.init('pid')
|
||||
ret.lateralTuning.pid.kf = 0.000038
|
||||
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0., 14., 23.], [0., 14., 23.]]
|
||||
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.01, 0.065, 0.2], [0.001, 0.015, 0.025]]
|
||||
|
||||
elif candidate in (CAR.SUBARU_OUTBACK, CAR.SUBARU_LEGACY, CAR.SUBARU_OUTBACK_2023):
|
||||
elif candidate in (CAR.SUBARU_OUTBACK, CAR.SUBARU_LEGACY):
|
||||
ret.steerActuatorDelay = 0.1
|
||||
|
||||
elif candidate in (CAR.SUBARU_FORESTER_PREGLOBAL, CAR.SUBARU_OUTBACK_PREGLOBAL_2018):
|
||||
|
||||
@@ -147,8 +147,8 @@ def create_es_dashstatus(packer, frame, dashstatus_msg, enabled, long_enabled, l
|
||||
"Signal4",
|
||||
"Conventional_Cruise",
|
||||
"Signal5",
|
||||
"Cruise_Disengaged",
|
||||
"Cruise_Activated",
|
||||
"Cruise_Disengaged_Dash",
|
||||
"Cruise_Activated_Dash",
|
||||
"Signal6",
|
||||
"Cruise_Set_Speed",
|
||||
"Cruise_Fault",
|
||||
@@ -165,8 +165,9 @@ def create_es_dashstatus(packer, frame, dashstatus_msg, enabled, long_enabled, l
|
||||
|
||||
if long_enabled:
|
||||
values["Cruise_State"] = 0
|
||||
values["Cruise_Activated"] = enabled
|
||||
values["Cruise_Disengaged"] = 0
|
||||
# TODO: Cruise_Activated_dash should respect gas pressed and standstill stock behavior
|
||||
values["Cruise_Activated_Dash"] = enabled
|
||||
values["Cruise_Disengaged_Dash"] = 0
|
||||
values["Car_Follow"] = int(lead_visible)
|
||||
|
||||
values["PCB_Off"] = 1 # AEB is not presevered, so show the PCB_Off on dash
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import copy
|
||||
from opendbc.can import CANDefine, CANParser
|
||||
from opendbc.car import Bus, structs
|
||||
from opendbc.car.carlog import carlog
|
||||
from opendbc.car.common.conversions import Conversions as CV
|
||||
from opendbc.car.interfaces import CarStateBase
|
||||
from opendbc.car.tesla.teslacan import get_steer_ctrl_type
|
||||
from opendbc.car.tesla.values import DBC, CANBUS, GEAR_MAP, STEER_THRESHOLD, CAR
|
||||
from opendbc.car.tesla.values import DBC, CANBUS, GEAR_MAP, STEER_THRESHOLD, TeslaFlags
|
||||
|
||||
from opendbc.sunnypilot.car.tesla.carstate_ext import CarStateExt
|
||||
|
||||
@@ -21,6 +22,8 @@ class CarState(CarStateBase, CarStateExt):
|
||||
self.autopark = False
|
||||
self.autopark_prev = False
|
||||
self.cruise_enabled_prev = False
|
||||
self.fsd14_error_logged = False
|
||||
self.suspected_fsd14 = False
|
||||
|
||||
self.hands_on_level = 0
|
||||
self.das_control = None
|
||||
@@ -117,10 +120,23 @@ class CarState(CarStateBase, CarStateExt):
|
||||
ret.stockLkas = cp_ap_party.vl["DAS_steeringControl"]["DAS_steeringControlType"] == lkas_ctrl_type # LANE_KEEP_ASSIST
|
||||
|
||||
# Stock Autosteer should be off (includes FSD)
|
||||
if self.CP.carFingerprint in (CAR.TESLA_MODEL_3, CAR.TESLA_MODEL_Y):
|
||||
# TODO: find for TESLA_MODEL_X and HW2.5 vehicles
|
||||
if not (self.CP.flags & TeslaFlags.MISSING_DAS_SETTINGS):
|
||||
ret.invalidLkasSetting = cp_ap_party.vl["DAS_settings"]["DAS_autosteerEnabled"] != 0
|
||||
else:
|
||||
pass
|
||||
|
||||
# Because we don't have FSD 14 detection outside of a set of FW, we should check if this FW is accidentally missing from FSD_14_FW
|
||||
# 1. If in Autosteer or FSD, already caught by invalidLkasSetting
|
||||
# 2. If in TACC and DAS ever sends ANGLE_CONTROL (1), we can infer it's trying to do LKAS on FSD 14+
|
||||
angle_control = cp_ap_party.vl["DAS_steeringControl"]["DAS_steeringControlType"] == 1 # ANGLE_CONTROL
|
||||
if not ret.invalidLkasSetting and angle_control and not self.CP.flags & TeslaFlags.FSD_14:
|
||||
self.suspected_fsd14 = True
|
||||
|
||||
if self.suspected_fsd14:
|
||||
ret.invalidLkasSetting = True
|
||||
if not self.fsd14_error_logged:
|
||||
carlog.error("FSD 14 detected, but FW not in FSD_14_FW set")
|
||||
self.fsd14_error_logged = True
|
||||
|
||||
# Buttons # ToDo: add Gap adjust button
|
||||
|
||||
# Messages needed by carcontroller
|
||||
|
||||
@@ -18,6 +18,7 @@ FW_VERSIONS = {
|
||||
b'TeMYG4_Main_0.0.0 (59),E4H014.29.0',
|
||||
b'TeMYG4_Main_0.0.0 (65),E4H015.01.0',
|
||||
b'TeMYG4_Main_0.0.0 (67),E4H015.02.1',
|
||||
b'TeMYG4_Main_0.0.0 (77),E4H015.04.5',
|
||||
b'TeMYG4_SingleECU_0.0.0 (33),E4S014.27',
|
||||
],
|
||||
},
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
from opendbc.car import get_safety_config, structs
|
||||
from opendbc.car import Bus, get_safety_config, structs
|
||||
from opendbc.car.interfaces import CarInterfaceBase
|
||||
from opendbc.car.tesla.carcontroller import CarController
|
||||
from opendbc.car.tesla.carstate import CarState
|
||||
from opendbc.car.tesla.values import TeslaSafetyFlags, TeslaFlags, CAR, FSD_14_FW, Ecu
|
||||
from opendbc.car.tesla.values import TeslaSafetyFlags, TeslaFlags, CANBUS, CAR, DBC, FSD_14_FW, Ecu
|
||||
from opendbc.car.tesla.radar_interface import RadarInterface, RADAR_START_ADDR
|
||||
|
||||
from opendbc.sunnypilot.car.tesla.values import TeslaFlagsSP, TeslaSafetyFlagsSP
|
||||
|
||||
@@ -10,6 +11,7 @@ from opendbc.sunnypilot.car.tesla.values import TeslaFlagsSP, TeslaSafetyFlagsSP
|
||||
class CarInterface(CarInterfaceBase):
|
||||
CarState = CarState
|
||||
CarController = CarController
|
||||
RadarInterface = RadarInterface
|
||||
|
||||
@staticmethod
|
||||
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams:
|
||||
@@ -22,7 +24,17 @@ class CarInterface(CarInterfaceBase):
|
||||
ret.steerAtStandstill = True
|
||||
|
||||
ret.steerControlType = structs.CarParams.SteerControlType.angle
|
||||
ret.radarUnavailable = True
|
||||
|
||||
# Model X and HW 2.5 vehicles are missing DAS_settings
|
||||
if 0x293 not in fingerprint[CANBUS.autopilot_party]:
|
||||
ret.flags |= TeslaFlags.MISSING_DAS_SETTINGS.value
|
||||
|
||||
# Radar support is intended to work for:
|
||||
# - Tesla Model 3 vehicles built approximately mid-2017 through early-2021
|
||||
# - Tesla Model Y vehicles built approximately mid-2020 through early-2021
|
||||
# - Vehicles equipped with the Continental ARS4-B radar (used on HW2 / HW2.5 / early HW3)
|
||||
# - Radar CAN lines must be tapped and connected to CAN bus 1 (normally not used for tesla vehicles)
|
||||
ret.radarUnavailable = RADAR_START_ADDR not in fingerprint[1] or Bus.radar not in DBC[candidate]
|
||||
|
||||
ret.alphaLongitudinalAvailable = True
|
||||
if alpha_long:
|
||||
|
||||
89
opendbc/car/tesla/radar_interface.py
Normal file
89
opendbc/car/tesla/radar_interface.py
Normal file
@@ -0,0 +1,89 @@
|
||||
from opendbc.can import CANParser
|
||||
from opendbc.car import Bus, structs
|
||||
from opendbc.car.interfaces import RadarInterfaceBase
|
||||
from opendbc.car.tesla.values import DBC
|
||||
|
||||
RADAR_START_ADDR = 0x410
|
||||
RADAR_MSG_COUNT = 80 # 40 points * 2 messages each
|
||||
|
||||
|
||||
def get_radar_can_parser(CP):
|
||||
if Bus.radar not in DBC[CP.carFingerprint]:
|
||||
return None
|
||||
|
||||
messages = [('RadarStatus', 16)]
|
||||
for i in range(RADAR_MSG_COUNT // 2):
|
||||
messages.extend([
|
||||
(f'RadarPoint{i}_A', 16),
|
||||
(f'RadarPoint{i}_B', 16),
|
||||
])
|
||||
|
||||
return CANParser(DBC[CP.carFingerprint][Bus.radar], messages, 1)
|
||||
|
||||
|
||||
class RadarInterface(RadarInterfaceBase):
|
||||
def __init__(self, CP, CP_SP):
|
||||
super().__init__(CP, CP_SP)
|
||||
self.updated_messages = set()
|
||||
self.trigger_msg = RADAR_START_ADDR + RADAR_MSG_COUNT - 1
|
||||
self.track_id = 0
|
||||
|
||||
self.radar_off_can = CP.radarUnavailable
|
||||
self.rcp = get_radar_can_parser(CP)
|
||||
|
||||
def update(self, can_strings):
|
||||
if self.radar_off_can or self.rcp is None:
|
||||
return super().update(None)
|
||||
|
||||
vls = self.rcp.update(can_strings)
|
||||
self.updated_messages.update(vls)
|
||||
|
||||
if self.trigger_msg not in self.updated_messages:
|
||||
return None
|
||||
|
||||
rr = self._update(self.updated_messages)
|
||||
self.updated_messages.clear()
|
||||
|
||||
return rr
|
||||
|
||||
def _update(self, updated_messages):
|
||||
ret = structs.RadarData()
|
||||
if self.rcp is None:
|
||||
return ret
|
||||
|
||||
if not self.rcp.can_valid:
|
||||
ret.errors.canError = True
|
||||
|
||||
radar_status = self.rcp.vl['RadarStatus']
|
||||
if radar_status['shortTermUnavailable']:
|
||||
ret.errors.radarUnavailableTemporary = True
|
||||
if radar_status['sensorBlocked'] or radar_status['vehDynamicsError']:
|
||||
ret.errors.radarFault = True
|
||||
|
||||
for i in range(RADAR_MSG_COUNT // 2):
|
||||
msg_a = self.rcp.vl[f'RadarPoint{i}_A']
|
||||
msg_b = self.rcp.vl[f'RadarPoint{i}_B']
|
||||
|
||||
# Make sure msg A and B are together
|
||||
if msg_a['Index'] != msg_b['Index2']:
|
||||
continue
|
||||
|
||||
if not msg_a['Tracked']:
|
||||
if i in self.pts:
|
||||
del self.pts[i]
|
||||
continue
|
||||
|
||||
if i not in self.pts:
|
||||
self.pts[i] = structs.RadarData.RadarPoint()
|
||||
self.pts[i].trackId = self.track_id
|
||||
self.track_id += 1
|
||||
|
||||
self.pts[i].dRel = msg_a['LongDist']
|
||||
self.pts[i].yRel = msg_a['LatDist']
|
||||
self.pts[i].vRel = msg_a['LongSpeed']
|
||||
self.pts[i].aRel = msg_a['LongAccel']
|
||||
self.pts[i].yvRel = msg_b['LatSpeed']
|
||||
self.pts[i].measured = bool(msg_a['Meas'])
|
||||
|
||||
ret.points = list(self.pts.values())
|
||||
return ret
|
||||
0
opendbc/car/tesla/tests/__init__.py
Normal file
0
opendbc/car/tesla/tests/__init__.py
Normal file
24
opendbc/car/tesla/tests/test_tesla.py
Normal file
24
opendbc/car/tesla/tests/test_tesla.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from opendbc.car import gen_empty_fingerprint
|
||||
from opendbc.car.tesla.interface import CarInterface
|
||||
from opendbc.car.tesla.radar_interface import RADAR_START_ADDR
|
||||
from opendbc.car.tesla.values import CAR
|
||||
|
||||
|
||||
class TestTeslaFingerprint:
|
||||
def test_radar_detection(self):
|
||||
# Test radar availability detection for cars with radar DBC defined
|
||||
for radar in (True, False):
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
if radar:
|
||||
fingerprint[1][RADAR_START_ADDR] = 8
|
||||
CP = CarInterface.get_params(CAR.TESLA_MODEL_3, fingerprint, [], False, False, False)
|
||||
assert CP.radarUnavailable != radar
|
||||
|
||||
def test_no_radar_car(self):
|
||||
# Model X doesn't have radar DBC defined, should always be unavailable
|
||||
for radar in (True, False):
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
if radar:
|
||||
fingerprint[1][RADAR_START_ADDR] = 8
|
||||
CP = CarInterface.get_params(CAR.TESLA_MODEL_X, fingerprint, [], False, False, False)
|
||||
assert CP.radarUnavailable # Always unavailable since no radar DBC
|
||||
@@ -48,6 +48,7 @@ class CAR(Platforms):
|
||||
TeslaCarDocsHW4("Tesla Model 3 (with HW4) 2024-25"),
|
||||
],
|
||||
CarSpecs(mass=1899., wheelbase=2.875, steerRatio=12.0),
|
||||
{Bus.party: 'tesla_model3_party', Bus.radar: 'tesla_radar_continental_generated', Bus.adas: 'tesla_model3_vehicle'},
|
||||
)
|
||||
TESLA_MODEL_Y = TeslaPlatformConfig(
|
||||
[
|
||||
@@ -55,6 +56,7 @@ class CAR(Platforms):
|
||||
TeslaCarDocsHW4("Tesla Model Y (with HW4) 2024-25"),
|
||||
],
|
||||
CarSpecs(mass=2072., wheelbase=2.890, steerRatio=12.0),
|
||||
{Bus.party: 'tesla_model3_party', Bus.radar: 'tesla_radar_continental_generated', Bus.adas: 'tesla_model3_vehicle'},
|
||||
)
|
||||
TESLA_MODEL_X = TeslaPlatformConfig(
|
||||
[TeslaCarDocsHW4("Tesla Model X (with HW4) 2024")],
|
||||
@@ -133,6 +135,7 @@ class TeslaSafetyFlags(IntFlag):
|
||||
class TeslaFlags(IntFlag):
|
||||
LONG_CONTROL = 1
|
||||
FSD_14 = 2
|
||||
MISSING_DAS_SETTINGS = 4
|
||||
|
||||
|
||||
DBC = CAR.create_dbc_map()
|
||||
|
||||
170
opendbc/car/tests/car_diff.py
Normal file → Executable file
170
opendbc/car/tests/car_diff.py
Normal file → Executable file
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import os
|
||||
import pickle
|
||||
@@ -5,23 +6,33 @@ import re
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import traceback
|
||||
import zstandard as zstd
|
||||
from tqdm import tqdm
|
||||
from tqdm.contrib.concurrent import process_map
|
||||
from urllib.request import urlopen
|
||||
from collections import defaultdict
|
||||
from concurrent.futures import ProcessPoolExecutor
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from comma_car_segments import get_comma_car_segments_database, get_url
|
||||
|
||||
from opendbc.car import structs
|
||||
from opendbc.car.can_definitions import CanData
|
||||
from opendbc.car.car_helpers import can_fingerprint, interfaces
|
||||
from opendbc.car.logreader import LogReader, decompress_stream
|
||||
|
||||
|
||||
TOLERANCE = 1e-4
|
||||
DIFF_BUCKET = "car_diff"
|
||||
IGNORE_FIELDS = ["cumLagMs", "canErrorCounter"]
|
||||
PADDING = 5
|
||||
|
||||
Diff = tuple[str, int, tuple[Any, Any], int]
|
||||
Ref = tuple[int, structs.CarState]
|
||||
Result = tuple[str, str, list[Diff], list[Ref] | None, list[structs.CarState] | None, str | None]
|
||||
|
||||
|
||||
def dict_diff(d1, d2, path="", ignore=None, tolerance=0):
|
||||
def dict_diff(d1: dict[str, Any], d2: dict[str, Any], path: str = "", ignore: list[str] | None = None, tolerance: float = 0) -> list[tuple]:
|
||||
ignore = ignore or []
|
||||
diffs = []
|
||||
for key in d1.keys() | d2.keys():
|
||||
@@ -39,23 +50,21 @@ def dict_diff(d1, d2, path="", ignore=None, tolerance=0):
|
||||
return diffs
|
||||
|
||||
|
||||
def load_can_messages(seg):
|
||||
def load_can_messages(seg: str) -> list[Any]:
|
||||
from comma_car_segments import get_url
|
||||
parts = seg.split("/")
|
||||
url = get_url(f"{parts[0]}/{parts[1]}", parts[2])
|
||||
msgs = LogReader(url, only_union_types=True)
|
||||
msgs = LogReader(url, only_union_types=True, sort_by_time=True)
|
||||
return [m for m in msgs if m.which() == 'can']
|
||||
|
||||
|
||||
def replay_segment(platform, can_msgs):
|
||||
from opendbc.car import gen_empty_fingerprint, structs
|
||||
from opendbc.car.can_definitions import CanData
|
||||
from opendbc.car.car_helpers import FRAME_FINGERPRINT, interfaces
|
||||
def replay_segment(platform: str, can_msgs: list[Any]) -> tuple[structs.CarParams, list[structs.CarState], list[int]]:
|
||||
_can_msgs = ([CanData(can.address, can.dat, can.src) for can in m.can] for m in can_msgs)
|
||||
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
for msg in can_msgs[:FRAME_FINGERPRINT]:
|
||||
for m in msg.can:
|
||||
if m.src < 64:
|
||||
fingerprint[m.src][m.address] = len(m.dat)
|
||||
def can_recv(wait_for_one: bool = False) -> list[list[CanData]]:
|
||||
return [next(_can_msgs, [])]
|
||||
|
||||
_, fingerprint = can_fingerprint(can_recv)
|
||||
|
||||
CarInterface = interfaces[platform]
|
||||
CP = CarInterface.get_params(platform, fingerprint, [], False, False, False)
|
||||
@@ -69,35 +78,39 @@ def replay_segment(platform, can_msgs):
|
||||
states.append(CI.update([(msg.logMonoTime, frames)]))
|
||||
CI.apply(CC, msg.logMonoTime)
|
||||
timestamps.append(msg.logMonoTime)
|
||||
return states, timestamps
|
||||
return CP, states, timestamps
|
||||
|
||||
|
||||
def process_segment(args):
|
||||
def process_segment(args: tuple) -> Result:
|
||||
platform, seg, ref_path, update = args
|
||||
try:
|
||||
can_msgs = load_can_messages(seg)
|
||||
states, timestamps = replay_segment(platform, can_msgs)
|
||||
CP, states, timestamps = replay_segment(platform, can_msgs)
|
||||
ref_file = Path(ref_path) / f"{platform}_{seg.replace('/', '_')}.zst"
|
||||
|
||||
if update:
|
||||
data = list(zip(timestamps, states, strict=True))
|
||||
data = {"cp": CP.to_dict(), "frames": list(zip(timestamps, states, strict=True))}
|
||||
ref_file.write_bytes(zstd.compress(pickle.dumps(data), 10))
|
||||
return (platform, seg, [], None)
|
||||
return (platform, seg, [], None, None, None)
|
||||
|
||||
if not ref_file.exists():
|
||||
return (platform, seg, [], "no ref")
|
||||
return (platform, seg, [], None, None, "no ref")
|
||||
|
||||
ref = pickle.loads(decompress_stream(ref_file.read_bytes()))
|
||||
ref_data = pickle.loads(decompress_stream(ref_file.read_bytes()))
|
||||
cp: dict[str, Any] = ref_data["cp"]
|
||||
ref: list[Ref] = ref_data["frames"]
|
||||
diffs = []
|
||||
for diff in dict_diff(cp, CP.to_dict(), path="carParams", ignore=IGNORE_FIELDS, tolerance=TOLERANCE):
|
||||
diffs.append((diff[1], -1, diff[2], 0))
|
||||
for i, ((ts, ref_state), state) in enumerate(zip(ref, states, strict=True)):
|
||||
for diff in dict_diff(ref_state.to_dict(), state.to_dict(), ignore=IGNORE_FIELDS, tolerance=TOLERANCE):
|
||||
diffs.append((diff[1], i, diff[2], ts))
|
||||
return (platform, seg, diffs, None)
|
||||
except Exception as e:
|
||||
return (platform, seg, [], str(e))
|
||||
return (platform, seg, diffs, ref, states, None)
|
||||
except Exception:
|
||||
return (platform, seg, [], None, None, traceback.format_exc())
|
||||
|
||||
|
||||
def get_changed_platforms(cwd, database, interfaces):
|
||||
def get_changed_platforms(cwd: Path, database: dict[str, Any], interfaces: dict[str, Any]) -> list[str]:
|
||||
git_ref = os.environ.get("GIT_REF", "origin/master")
|
||||
changed = subprocess.check_output(["git", "diff", "--name-only", f"{git_ref}...HEAD"], cwd=cwd, encoding='utf8').strip()
|
||||
brands = set()
|
||||
@@ -110,30 +123,26 @@ def get_changed_platforms(cwd, database, interfaces):
|
||||
return [p for p in interfaces if any(b in p.lower() for b in brands) and p in database]
|
||||
|
||||
|
||||
def download_refs(ref_path, platforms, segments):
|
||||
def download_refs(ref_path: Path, platforms: list[str], segments: dict[str, list[str]]) -> None:
|
||||
base_url = f"https://raw.githubusercontent.com/commaai/ci-artifacts/refs/heads/{DIFF_BUCKET}"
|
||||
for platform in platforms:
|
||||
for platform in tqdm(platforms):
|
||||
for seg in segments.get(platform, []):
|
||||
filename = f"{platform}_{seg.replace('/', '_')}.zst"
|
||||
try:
|
||||
with urlopen(f"{base_url}/{filename}") as resp:
|
||||
(Path(ref_path) / filename).write_bytes(resp.read())
|
||||
except Exception:
|
||||
pass
|
||||
with urlopen(f"{base_url}/{filename}") as resp:
|
||||
(Path(ref_path) / filename).write_bytes(resp.read())
|
||||
|
||||
|
||||
def run_replay(platforms, segments, ref_path, update, workers=4):
|
||||
def run_replay(platforms: list[str], segments: dict[str, list[str]], ref_path: Path, update: bool, workers: int = 4) -> list[Result]:
|
||||
work = [(platform, seg, ref_path, update)
|
||||
for platform in platforms for seg in segments.get(platform, [])]
|
||||
with ProcessPoolExecutor(max_workers=workers) as pool:
|
||||
return list(pool.map(process_segment, work))
|
||||
return process_map(process_segment, work, max_workers=workers)
|
||||
|
||||
|
||||
# ASCII waveforms helpers
|
||||
def find_edges(vals, init):
|
||||
def find_edges(vals: list[bool]) -> tuple[list[int], list[int]]:
|
||||
rises = []
|
||||
falls = []
|
||||
prev = init
|
||||
prev = vals[0]
|
||||
for i, val in enumerate(vals):
|
||||
if val and not prev:
|
||||
rises.append(i)
|
||||
@@ -143,10 +152,10 @@ def find_edges(vals, init):
|
||||
return rises, falls
|
||||
|
||||
|
||||
def render_waveform(label, vals, init):
|
||||
def render_waveform(label: str, vals: list[bool]) -> str:
|
||||
wave = {(False, False): "_", (True, True): "‾", (False, True): "/", (True, False): "\\"}
|
||||
line = f" {label}:".ljust(12)
|
||||
prev = init
|
||||
prev = vals[0]
|
||||
for val in vals:
|
||||
line += wave[(prev, val)]
|
||||
prev = val
|
||||
@@ -155,7 +164,7 @@ def render_waveform(label, vals, init):
|
||||
return line
|
||||
|
||||
|
||||
def format_timing(edge_type, master_edges, pr_edges, ms_per_frame):
|
||||
def format_timing(edge_type: str, master_edges: list[int], pr_edges: list[int], ms_per_frame: float) -> str | None:
|
||||
if not master_edges or not pr_edges:
|
||||
return None
|
||||
delta = pr_edges[0] - master_edges[0]
|
||||
@@ -166,7 +175,7 @@ def format_timing(edge_type, master_edges, pr_edges, ms_per_frame):
|
||||
return " " * 12 + f"{edge_type}: PR {direction} by {abs(delta)} frames ({ms}ms)"
|
||||
|
||||
|
||||
def group_frames(diffs, max_gap=15):
|
||||
def group_frames(diffs: list[Diff], max_gap: int = 15) -> list[list[Diff]]:
|
||||
groups = []
|
||||
current = [diffs[0]]
|
||||
for diff in diffs[1:]:
|
||||
@@ -181,28 +190,25 @@ def group_frames(diffs, max_gap=15):
|
||||
return groups
|
||||
|
||||
|
||||
def build_signals(group):
|
||||
def build_signals(group: list[Diff], ref: list[Ref], states: list[structs.CarState], field: str) -> tuple[list[Any], list[Any], int, int]:
|
||||
_, first_frame, _, _ = group[0]
|
||||
_, last_frame, (final_master, _), _ = group[-1]
|
||||
start = max(0, first_frame - 5)
|
||||
end = last_frame + 6
|
||||
init = not final_master
|
||||
diff_at = {frame: (m, p) for _, frame, (m, p), _ in group}
|
||||
_, last_frame, _, _ = group[-1]
|
||||
start = max(0, first_frame - PADDING)
|
||||
end = min(last_frame + PADDING + 1, len(ref))
|
||||
master_vals = []
|
||||
pr_vals = []
|
||||
master = init
|
||||
pr = init
|
||||
for frame in range(start, end):
|
||||
if frame in diff_at:
|
||||
master, pr = diff_at[frame]
|
||||
elif frame > last_frame:
|
||||
master = pr = final_master
|
||||
master_vals.append(master)
|
||||
pr_vals.append(pr)
|
||||
return master_vals, pr_vals, init, start, end
|
||||
mval = ref[frame][1].to_dict()
|
||||
pval = states[frame].to_dict()
|
||||
for k in field.split("."):
|
||||
mval = mval.get(k) if isinstance(mval, dict) else None
|
||||
pval = pval.get(k) if isinstance(pval, dict) else None
|
||||
master_vals.append(mval)
|
||||
pr_vals.append(pval)
|
||||
return master_vals, pr_vals, start, end
|
||||
|
||||
|
||||
def format_numeric_diffs(diffs):
|
||||
def format_numeric_diffs(diffs: list[Diff]) -> list[str]:
|
||||
lines = []
|
||||
for _, frame, (old_val, new_val), _ in diffs[:10]:
|
||||
lines.append(f" frame {frame}: {old_val} -> {new_val}")
|
||||
@@ -211,7 +217,7 @@ def format_numeric_diffs(diffs):
|
||||
return lines
|
||||
|
||||
|
||||
def format_boolean_diffs(diffs):
|
||||
def format_boolean_diffs(diffs: list[Diff], ref: list[Ref], states: list[structs.CarState], field: str) -> list[str]:
|
||||
_, first_frame, _, first_ts = diffs[0]
|
||||
_, last_frame, _, last_ts = diffs[-1]
|
||||
frame_time = last_frame - first_frame
|
||||
@@ -219,14 +225,12 @@ def format_boolean_diffs(diffs):
|
||||
ms = time_ms / frame_time if frame_time else 10.0
|
||||
lines = []
|
||||
for group in group_frames(diffs):
|
||||
master_vals, pr_vals, init, start, end = build_signals(group)
|
||||
master_rises, master_falls = find_edges(master_vals, init)
|
||||
pr_rises, pr_falls = find_edges(pr_vals, init)
|
||||
if bool(master_rises) != bool(pr_rises) or bool(master_falls) != bool(pr_falls):
|
||||
continue
|
||||
master_vals, pr_vals, start, end = build_signals(group, ref, states, field)
|
||||
master_rises, master_falls = find_edges(master_vals)
|
||||
pr_rises, pr_falls = find_edges(pr_vals)
|
||||
lines.append(f"\n frames {start}-{end - 1}")
|
||||
lines.append(render_waveform("master", master_vals, init))
|
||||
lines.append(render_waveform("PR", pr_vals, init))
|
||||
lines.append(render_waveform("master", master_vals))
|
||||
lines.append(render_waveform("PR", pr_vals))
|
||||
for edge_type, master_edges, pr_edges in [("rise", master_rises, pr_rises), ("fall", master_falls, pr_falls)]:
|
||||
msg = format_timing(edge_type, master_edges, pr_edges, ms)
|
||||
if msg:
|
||||
@@ -234,19 +238,18 @@ def format_boolean_diffs(diffs):
|
||||
return lines
|
||||
|
||||
|
||||
def format_diff(diffs):
|
||||
def format_diff(diffs: list[Diff], ref: list[Ref], states: list[structs.CarState], field: str) -> list[str]:
|
||||
if not diffs:
|
||||
return []
|
||||
_, _, (old, new), _ = diffs[0]
|
||||
is_bool = isinstance(old, bool) and isinstance(new, bool)
|
||||
if is_bool:
|
||||
return format_boolean_diffs(diffs)
|
||||
return format_boolean_diffs(diffs, ref, states, field)
|
||||
return format_numeric_diffs(diffs)
|
||||
|
||||
|
||||
def main(platform=None, segments_per_platform=10, update_refs=False, all_platforms=False):
|
||||
from opendbc.car.car_helpers import interfaces
|
||||
|
||||
def main(platform: str | None = None, segments_per_platform: int = 10, update_refs: bool = False, all_platforms: bool = False) -> int:
|
||||
from comma_car_segments import get_comma_car_segments_database
|
||||
cwd = Path(__file__).resolve().parents[3]
|
||||
ref_path = cwd / DIFF_BUCKET
|
||||
if not update_refs:
|
||||
@@ -262,8 +265,12 @@ def main(platform=None, segments_per_platform=10, update_refs=False, all_platfor
|
||||
else:
|
||||
platforms = get_changed_platforms(cwd, database, interfaces)
|
||||
|
||||
print("## Car behavior report")
|
||||
print("Replays driving segments through this PR and compares the behavior to master.")
|
||||
print("Please review any changes carefully to ensure they are expected.\n")
|
||||
|
||||
if not platforms:
|
||||
print("No car changes detected", file=sys.stderr)
|
||||
print("✅ No changes detected")
|
||||
return 0
|
||||
|
||||
segments = {p: database.get(p, [])[:segments_per_platform] for p in platforms}
|
||||
@@ -272,35 +279,36 @@ def main(platform=None, segments_per_platform=10, update_refs=False, all_platfor
|
||||
|
||||
if update_refs:
|
||||
results = run_replay(platforms, segments, ref_path, update=True)
|
||||
errors = [e for _, _, _, e in results if e]
|
||||
errors = [e for _, _, _, _, _, e in results if e]
|
||||
assert len(errors) == 0, f"Segment failures: {errors}"
|
||||
print(f"Generated {n_segments} refs to {ref_path}")
|
||||
return 0
|
||||
|
||||
download_refs(ref_path, platforms, segments)
|
||||
results = run_replay(platforms, segments, ref_path, update=False)
|
||||
|
||||
with_diffs = [(p, s, d) for p, s, d, e in results if d]
|
||||
errors = [(p, s, e) for p, s, d, e in results if e]
|
||||
with_diffs = [(platform, seg, diffs, ref, states)
|
||||
for platform, seg, diffs, ref, states, err in results if diffs]
|
||||
errors = [(platform, seg, err) for platform, seg, diffs, ref, states, err in results if err]
|
||||
n_passed = len(results) - len(with_diffs) - len(errors)
|
||||
|
||||
print(f"\nResults: {n_passed} passed, {len(with_diffs)} with diffs, {len(errors)} errors")
|
||||
icon = "⚠️" if with_diffs else "✅"
|
||||
print(f"\n{icon} {len(with_diffs)} changed, {n_passed} passed, {len(errors)} errors")
|
||||
|
||||
for plat, seg, err in errors:
|
||||
print(f"\nERROR {plat} - {seg}: {err}")
|
||||
|
||||
if with_diffs:
|
||||
print("```")
|
||||
for plat, seg, diffs in with_diffs:
|
||||
print("<details><summary><b>Show changes</b></summary>\n\n```")
|
||||
for plat, seg, diffs, ref, states in with_diffs:
|
||||
print(f"\n{plat} - {seg}")
|
||||
by_field = defaultdict(list)
|
||||
for d in diffs:
|
||||
by_field[d[0]].append(d)
|
||||
for field, fd in sorted(by_field.items()):
|
||||
print(f" {field} ({len(fd)} diffs)")
|
||||
for line in format_diff(fd):
|
||||
print(f"\n {field} ({len(fd)} diffs)")
|
||||
for line in format_diff(fd, ref, states, field):
|
||||
print(line)
|
||||
print("```")
|
||||
print("```\n</details>")
|
||||
|
||||
return 1 if errors else 0
|
||||
|
||||
|
||||
@@ -140,6 +140,7 @@ routes = [
|
||||
CarTestRoute("f29e2b57a55e7ad5/2021-03-24--20-52-38", HONDA.HONDA_ACCORD), # hybrid, 2021 with new style HUD msgs
|
||||
CarTestRoute("1ad763dd22ef1a0e/2020-02-29--18-37-03", HONDA.HONDA_CRV_5G),
|
||||
CarTestRoute("0a96f86fcfe35964/2020-02-05--07-25-51", HONDA.HONDA_ODYSSEY),
|
||||
CarTestRoute("7817fe954aff07b8/00000001--fdaaf36c4f", HONDA.HONDA_ODYSSEY_TWN),
|
||||
CarTestRoute("d7233a428eb7d0b5/00000001--9b99b04d43", HONDA.HONDA_ODYSSEY_5G_MMR),
|
||||
CarTestRoute("d83f36766f8012a5/2020-02-05--18-42-21", HONDA.HONDA_CIVIC_BOSCH_DIESEL),
|
||||
CarTestRoute("f0890d16a07a236b/2021-05-25--17-27-22", HONDA.HONDA_INSIGHT),
|
||||
@@ -157,6 +158,7 @@ routes = [
|
||||
# CarTestRoute("56b2cf1dacdcd033/00000017--d24ffdb376", HONDA.HONDA_CITY_7G), # Brazilian model
|
||||
CarTestRoute("2dc4489d7e1410ca/00000001--bbec3f5117", HONDA.HONDA_CRV_6G),
|
||||
CarTestRoute("a703d058f4e05aeb/00000008--f169423024", HONDA.HONDA_PASSPORT_4G),
|
||||
CarTestRoute("ad9840558640c31d/000001f2--026c4f6275", HONDA.ACURA_TLX_2G_MMR),
|
||||
|
||||
CarTestRoute("87d7f06ade479c2e/2023-09-11--23-30-11", HYUNDAI.HYUNDAI_AZERA_6TH_GEN),
|
||||
CarTestRoute("66189dd8ec7b50e6/2023-09-20--07-02-12", HYUNDAI.HYUNDAI_AZERA_HEV_6TH_GEN),
|
||||
|
||||
@@ -2,6 +2,7 @@ import os
|
||||
import math
|
||||
import hypothesis.strategies as st
|
||||
import pytest
|
||||
from functools import cache
|
||||
from hypothesis import Phase, given, settings
|
||||
from collections.abc import Callable
|
||||
from typing import Any
|
||||
@@ -27,7 +28,8 @@ DLC_TO_LEN = [0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64]
|
||||
MAX_EXAMPLES = int(os.environ.get('MAX_EXAMPLES', '15'))
|
||||
|
||||
|
||||
def get_fuzzy_car_interface(car_name: str, draw: DrawType) -> CarInterfaceBase:
|
||||
@cache
|
||||
def get_fuzzy_strategy():
|
||||
# Fuzzy CAN fingerprints and FW versions to test more states of the CarInterface
|
||||
fingerprint_strategy = st.fixed_dictionaries({0: st.dictionaries(st.integers(min_value=0, max_value=0x800),
|
||||
st.sampled_from(DLC_TO_LEN))})
|
||||
@@ -44,8 +46,11 @@ def get_fuzzy_car_interface(car_name: str, draw: DrawType) -> CarInterfaceBase:
|
||||
'car_fw': car_fw_strategy,
|
||||
'alpha_long': st.booleans(),
|
||||
})
|
||||
return params_strategy
|
||||
|
||||
params: dict = draw(params_strategy)
|
||||
|
||||
def get_fuzzy_car_interface(car_name: str, draw: DrawType) -> CarInterfaceBase:
|
||||
params: dict = draw(get_fuzzy_strategy())
|
||||
# reduce search space by duplicating CAN fingerprints across all buses
|
||||
params['fingerprints'] |= {key + 1: params['fingerprints'][0] for key in range(6)}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ class TestCarDocs:
|
||||
for car in self.all_cars:
|
||||
with subtests.test(car=car.name):
|
||||
# honda sanity check, it's the definition of a no torque star
|
||||
if car.car_fingerprint in (HONDA.HONDA_ACCORD, HONDA.HONDA_CIVIC, HONDA.HONDA_CRV, HONDA.HONDA_ODYSSEY, HONDA.HONDA_PILOT):
|
||||
if car.car_fingerprint in (HONDA.HONDA_ACCORD, HONDA.HONDA_CIVIC, HONDA.HONDA_CRV, HONDA.HONDA_ODYSSEY, HONDA.HONDA_ODYSSEY_TWN, HONDA.HONDA_PILOT):
|
||||
assert car.row[Column.STEERING_TORQUE] == Star.EMPTY, f"{car.name} has full torque star"
|
||||
elif car.brand in ("toyota", "hyundai"):
|
||||
assert car.row[Column.STEERING_TORQUE] != Star.EMPTY, f"{car.name} has no torque star"
|
||||
|
||||
@@ -101,7 +101,11 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
|
||||
"HONDA_ODYSSEY_5G_MMR" = [0.9, 0.9, 0.2]
|
||||
"HONDA_NBOX_2G" = [1.2, 1.2, 0.2]
|
||||
"ACURA_TLX_2G" = [1.2, 1.2, 0.15]
|
||||
"ACURA_TLX_2G_MMR" = [1.7, 1.7, 0.16]
|
||||
"PORSCHE_MACAN_MK1" = [2.0, 2.0, 0.2]
|
||||
"LEXUS_LS" = [1.35, 1.7, 0.17]
|
||||
"TOYOTA_RAV4_PRIME" = [1.7, 2.0, 0.14]
|
||||
"TOYOTA_RAV4_TSS2_2022" = [1.9, 1.9304407208090029, 0.112174]
|
||||
|
||||
# Dashcam or fallback configured as ideal car
|
||||
"MOCK" = [10.0, 10, 0.0]
|
||||
|
||||
@@ -69,9 +69,8 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
|
||||
"TOYOTA_PRIUS" = [1.60, 1.5023147650693636, 0.151515]
|
||||
"TOYOTA_PRIUS_TSS2" = [1.972600, 1.9104337425537743, 0.170968]
|
||||
"TOYOTA_RAV4" = [2.085695074355425, 2.2142832316984733, 0.13339165270103975]
|
||||
"TOYOTA_RAV4_TSS2" = [2.279239424615458, 2.087101966779332, 0.13682208413446817]
|
||||
"TOYOTA_RAV4_TSS2" = [1.9557514786720276, 2.087101966779332, 0.12075843289494514]
|
||||
"TOYOTA_RAV4H" = [1.9796257271652042, 1.7503987331707576, 0.14628860048885406]
|
||||
"TOYOTA_RAV4_TSS2_2022" = [2.241883248393209, 1.9304407208090029, 0.112174]
|
||||
"TOYOTA_SIENNA" = [1.689726, 1.3208264576110418, 0.140456]
|
||||
"TOYOTA_YARIS" = [2.22984, 1.86145, 0.168189]
|
||||
"VOLKSWAGEN_ARTEON_MK1" = [1.45136518053819, 1.3639364049316804, 0.23806361745695032]
|
||||
|
||||
@@ -9,15 +9,13 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
|
||||
|
||||
"TOYOTA_ALPHARD_TSS2" = "TOYOTA_SIENNA"
|
||||
"TOYOTA_PRIUS_V" = "TOYOTA_PRIUS"
|
||||
"TOYOTA_RAV4_PRIME" = "TOYOTA_RAV4_TSS2"
|
||||
"TOYOTA_SIENNA_4TH_GEN" = "TOYOTA_RAV4_TSS2"
|
||||
"TOYOTA_SIENNA_4TH_GEN" = "TOYOTA_RAV4_PRIME"
|
||||
"LEXUS_IS" = "LEXUS_NX"
|
||||
"LEXUS_CTH" = "LEXUS_NX"
|
||||
"LEXUS_ES" = "TOYOTA_CAMRY"
|
||||
"LEXUS_RC" = "LEXUS_NX_TSS2"
|
||||
"LEXUS_RC_TSS2" = "LEXUS_NX_TSS2"
|
||||
"LEXUS_LC_TSS2" = "LEXUS_NX_TSS2"
|
||||
"LEXUS_LS" = "LEXUS_NX"
|
||||
|
||||
"KIA_OPTIMA_G4" = "HYUNDAI_SONATA"
|
||||
"KIA_OPTIMA_G4_FL" = "HYUNDAI_SONATA"
|
||||
@@ -52,6 +50,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
|
||||
"HONDA_CRV_EU" = "HONDA_CRV"
|
||||
"HONDA_CIVIC_BOSCH_DIESEL" = "HONDA_CIVIC_BOSCH"
|
||||
"HONDA_E" = "HONDA_CIVIC_BOSCH"
|
||||
"HONDA_ODYSSEY_TWN" = "HONDA_ODYSSEY"
|
||||
|
||||
"BUICK_LACROSSE" = "CHEVROLET_VOLT"
|
||||
"BUICK_REGAL" = "CHEVROLET_VOLT"
|
||||
|
||||
@@ -31,7 +31,7 @@ MAX_PITCH_COMPENSATION = 1.5 # m/s^2
|
||||
# LKA limits
|
||||
# EPS faults if you apply torque while the steering rate is above 100 deg/s for too long
|
||||
MAX_STEER_RATE = 100 # deg/s
|
||||
MAX_STEER_RATE_FRAMES = 18 # tx control frames needed before torque can be cut
|
||||
MAX_STEER_RATE_FRAMES = 17 # tx control frames needed before torque can be cut
|
||||
|
||||
# EPS allows user torque above threshold for 50 frames before permanently faulting
|
||||
MAX_USER_TORQUE = 500
|
||||
|
||||
@@ -1442,21 +1442,26 @@ FW_VERSIONS = {
|
||||
CAR.LEXUS_GS_F: {
|
||||
(Ecu.engine, 0x7e0, None): [
|
||||
b'\x0233075200\x00\x00\x00\x00\x00\x00\x00\x00530B9000\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||
b'\x02330Y8000\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||
],
|
||||
(Ecu.abs, 0x7b0, None): [
|
||||
b'F152630700\x00\x00\x00\x00\x00\x00',
|
||||
b'F152630400\x00\x00\x00\x00\x00\x00',
|
||||
],
|
||||
(Ecu.dsu, 0x791, None): [
|
||||
b'881513016200\x00\x00\x00\x00',
|
||||
b'881513011300\x00\x00\x00\x00',
|
||||
],
|
||||
(Ecu.eps, 0x7a1, None): [
|
||||
b'8965B30551\x00\x00\x00\x00\x00\x00',
|
||||
b'8965B30431\x00\x00\x00\x00\x00\x00',
|
||||
],
|
||||
(Ecu.fwdRadar, 0x750, 0xf): [
|
||||
b'8821F4702000\x00\x00\x00\x00',
|
||||
],
|
||||
(Ecu.fwdCamera, 0x750, 0x6d): [
|
||||
b'8646F3002100\x00\x00\x00\x00',
|
||||
b'8646F3001200\x00\x00\x00\x00',
|
||||
],
|
||||
},
|
||||
CAR.LEXUS_NX: {
|
||||
|
||||
@@ -76,24 +76,7 @@ class CarInterface(CarInterfaceBase):
|
||||
# https://engage.toyota.com/static/images/toyota_safety_sense/TSS_Applicability_Chart.pdf
|
||||
stop_and_go = candidate != CAR.TOYOTA_AVALON
|
||||
|
||||
elif candidate in (CAR.TOYOTA_RAV4_TSS2, CAR.TOYOTA_RAV4_TSS2_2022, CAR.TOYOTA_RAV4_TSS2_2023, CAR.TOYOTA_RAV4_PRIME, CAR.TOYOTA_SIENNA_4TH_GEN):
|
||||
ret.lateralTuning.init('pid')
|
||||
ret.lateralTuning.pid.kiBP = [0.0]
|
||||
ret.lateralTuning.pid.kpBP = [0.0]
|
||||
ret.lateralTuning.pid.kpV = [0.6]
|
||||
ret.lateralTuning.pid.kiV = [0.1]
|
||||
ret.lateralTuning.pid.kf = 0.00007818594
|
||||
|
||||
# 2019+ RAV4 TSS2 uses two different steering racks and specific tuning seems to be necessary.
|
||||
# See https://github.com/commaai/openpilot/pull/21429#issuecomment-873652891
|
||||
for fw in car_fw:
|
||||
if fw.ecu == "eps" and (fw.fwVersion.startswith(b'\x02') or fw.fwVersion in [b'8965B42181\x00\x00\x00\x00\x00\x00']):
|
||||
ret.lateralTuning.pid.kpV = [0.15]
|
||||
ret.lateralTuning.pid.kiV = [0.05]
|
||||
ret.lateralTuning.pid.kf = 0.00004
|
||||
break
|
||||
|
||||
elif candidate in (CAR.TOYOTA_CHR, CAR.TOYOTA_CAMRY, CAR.TOYOTA_SIENNA, CAR.LEXUS_CTH, CAR.LEXUS_NX):
|
||||
elif candidate in (CAR.TOYOTA_CHR, CAR.TOYOTA_CAMRY, CAR.TOYOTA_SIENNA, CAR.LEXUS_CTH, CAR.LEXUS_LS, CAR.LEXUS_NX):
|
||||
# TODO: Some of these platforms are not advertised to have full range ACC, do they really all have sng?
|
||||
stop_and_go = True
|
||||
|
||||
|
||||
@@ -219,7 +219,7 @@ def dyn_ss_sol(sa: float, u: float, roll: float, VM: VehicleModel) -> np.ndarray
|
||||
"""
|
||||
A, B = create_dyn_state_matrices(u, VM)
|
||||
inp = np.array([[sa], [roll]])
|
||||
return -solve(A, B) @ inp # type: ignore
|
||||
return -solve(A, B) @ inp
|
||||
|
||||
|
||||
def calc_slip_factor(VM: VehicleModel) -> float:
|
||||
|
||||
@@ -1128,11 +1128,13 @@ FW_VERSIONS = {
|
||||
b'\xf1\x8795B906259BM\xf1\x890001',
|
||||
b'\xf1\x8795B90652013\xf1\x893485',
|
||||
b'\xf1\x8795B90654002\xf1\x893495',
|
||||
b'\xf1\x8795B907551AD\xf1\x890001',
|
||||
b'\xf1\x8795B907551D \xf1\x890006',
|
||||
],
|
||||
(Ecu.transmission, 0x7e1, None): [
|
||||
b'\xf1\x8795B927156CE\xf1\x890022',
|
||||
b'\xf1\x8795B927156JH\xf1\x890001',
|
||||
b'\xf1\x8795B927156KD\xf1\x890001',
|
||||
b'\xf1\x8795B927156KK\xf1\x890001',
|
||||
b'\xf1\x8795B927156KP\xf1\x890001',
|
||||
b'\xf1\x8795B927156R \xf1\x890021',
|
||||
@@ -1141,6 +1143,7 @@ FW_VERSIONS = {
|
||||
b'\xf1\x8795B959655F \xf1\x890130\xf1\x82\x05065Q033513',
|
||||
b'\xf1\x8795B959655F \xf1\x890130\xf1\x82\x050682033514',
|
||||
b'\xf1\x8795B959655G \xf1\x890150\xf1\x82\x0506B1033514',
|
||||
b'\xf1\x8795B959655G \xf1\x890150\xf1\x82\x0506CG033517',
|
||||
b'\xf1\x8795B959655G \xf1\x890150\xf1\x82\x0506CJ02D417',
|
||||
],
|
||||
(Ecu.eps, 0x712, None): [
|
||||
@@ -1150,6 +1153,7 @@ FW_VERSIONS = {
|
||||
(Ecu.fwdRadar, 0x757, None): [
|
||||
b'\xf1\x8795B907567B\x00\xf1\x890800\xf1\x82108',
|
||||
b'\xf1\x8795B907567G\x00\xf1\x890410\xf1\x82104',
|
||||
b'\xf1\x8795B907567H\x00\xf1\x890430\xf1\x82104',
|
||||
b'\xf1\x8795B907567J \xf1\x890440\xf1\x82104',
|
||||
],
|
||||
},
|
||||
|
||||
@@ -85,6 +85,13 @@ BO_ 490 VEHICLE_DYNAMICS: 8 VSA
|
||||
SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EON
|
||||
SG_ CHECKSUM : 59|4@0+ (1,0) [0|3] "" EON
|
||||
|
||||
BO_ 547 BRAKE_HOLD_HYBRID_ALT: 6 XXX
|
||||
SG_ BRAKE_HOLD_FAULT_BIT : 33|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ BRAKE_HOLD_ENABLED : 37|2@0+ (1,0) [0|7] "" XXX
|
||||
SG_ BRAKE_HOLD_ACTIVE : 38|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ CHECKSUM : 43|4@0+ (1,0) [0|15] "" XXX
|
||||
SG_ COUNTER : 45|2@0+ (1,0) [0|3] "" XXX
|
||||
|
||||
BO_ 597 ROUGH_WHEEL_SPEED: 8 VSA
|
||||
SG_ WHEEL_SPEED_FL : 7|8@0+ (1,0) [0|255] "kph" EON
|
||||
SG_ WHEEL_SPEED_FR : 15|8@0+ (1,0) [0|255] "kph" EON
|
||||
|
||||
@@ -35,13 +35,6 @@ BO_ 506 BRAKE_COMMAND: 8 ADAS
|
||||
SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EBCM
|
||||
SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EBCM
|
||||
|
||||
BO_ 547 BRAKE_HOLD_HYBRID_ALT: 6 XXX
|
||||
SG_ BRAKE_HOLD_FAULT_BIT : 33|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ BRAKE_HOLD_ENABLED : 37|2@0+ (1,0) [0|7] "" XXX
|
||||
SG_ BRAKE_HOLD_ACTIVE : 38|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ CHECKSUM : 43|4@0+ (1,0) [0|15] "" XXX
|
||||
SG_ COUNTER : 45|2@0+ (1,0) [0|3] "" XXX
|
||||
|
||||
BO_ 892 CRUISE_PARAMS: 8 PCM
|
||||
SG_ CRUISE_SPEED_OFFSET : 31|8@0- (0.1,0) [-128|127] "kph" EON
|
||||
SG_ CHECKSUM : 59|4@0+ (1,0) [0|3] "" EON
|
||||
|
||||
17
opendbc/dbc/generator/honda/_steering_control_c.dbc
Normal file
17
opendbc/dbc/generator/honda/_steering_control_c.dbc
Normal file
@@ -0,0 +1,17 @@
|
||||
BO_ 404 STEERING_CONTROL: 4 EON
|
||||
SG_ SET_ME_X00 : 22|7@0+ (1,0) [0|127] "" EPS
|
||||
SG_ STEER_TORQUE_REQUEST : 23|1@0+ (1,0) [0|1] "" EPS
|
||||
SG_ COUNTER : 29|2@0+ (1,0) [0|15] "" EPS
|
||||
SG_ CHECKSUM : 27|4@0+ (1,0) [0|3] "" EPS
|
||||
SG_ STEER_TORQUE : 7|16@0- (-1,0) [-32767|32767] "" EPS
|
||||
|
||||
BO_ 399 STEER_STATUS: 7 EPS
|
||||
SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-2985|2985] "tbd" EON
|
||||
SG_ STEER_ANGLE_RATE : 23|16@0- (-0.1,0) [-31000|31000] "deg/s" EON
|
||||
SG_ STEER_STATUS : 43|4@0+ (1,0) [0|15] "" EON
|
||||
SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON
|
||||
SG_ STEER_CONFIG_INDEX : 43|4@0+ (1,0) [0|15] "" EON
|
||||
SG_ CHECKSUM : 51|4@0+ (1,0) [0|15] "" EON
|
||||
SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON
|
||||
|
||||
VAL_ 399 STEER_STATUS 7 "permanent_fault" 6 "tmp_fault" 5 "fault_1" 4 "no_torque_alert_2" 3 "low_speed_lockout" 2 "no_torque_alert_1" 1 "driver_steering" 0 "normal" ;
|
||||
7
opendbc/dbc/generator/honda/_steering_sensors_c.dbc
Normal file
7
opendbc/dbc/generator/honda/_steering_sensors_c.dbc
Normal file
@@ -0,0 +1,7 @@
|
||||
CM_ "steer_angle_rate is negative vs _steering_sensors_b.dbc";
|
||||
|
||||
BO_ 342 STEERING_SENSORS: 6 EPS
|
||||
SG_ STEER_ANGLE : 7|16@0- (-0.1,0) [-500|500] "deg" EON
|
||||
SG_ STEER_ANGLE_RATE : 23|16@0- (1,0) [-3000|3000] "deg/s" EON
|
||||
SG_ COUNTER : 45|2@0+ (1,0) [0|3] "" EON
|
||||
SG_ CHECKSUM : 43|4@0+ (1,0) [0|15] "" EON
|
||||
7
opendbc/dbc/generator/honda/honda_odyssey_twn_2018.dbc
Normal file
7
opendbc/dbc/generator/honda/honda_odyssey_twn_2018.dbc
Normal file
@@ -0,0 +1,7 @@
|
||||
CM_ "IMPORT _honda_common.dbc";
|
||||
CM_ "IMPORT _nidec_common.dbc";
|
||||
CM_ "IMPORT _lkas_hud_5byte.dbc";
|
||||
CM_ "IMPORT _nidec_scm_group_a.dbc";
|
||||
CM_ "IMPORT _steering_sensors_c.dbc";
|
||||
CM_ "IMPORT _steering_control_c.dbc";
|
||||
CM_ "IMPORT _gearbox_common.dbc";
|
||||
@@ -45,8 +45,8 @@ BO_ 64 Throttle: 8 XXX
|
||||
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
|
||||
SG_ Signal1 : 12|4@1+ (1,0) [0|15] "" XXX
|
||||
SG_ Engine_RPM : 16|12@1+ (1,0) [0|4095] "" XXX
|
||||
SG_ Signal2 : 28|4@1+ (1,0) [0|15] "" XXX
|
||||
SG_ Engine_RPM : 16|13@1+ (1,0) [0|8191] "" XXX
|
||||
SG_ Neutral : 31|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ Throttle_Pedal : 32|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ Throttle_Cruise : 40|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ Throttle_Combo : 48|8@1+ (1,0) [0|255] "" XXX
|
||||
@@ -110,6 +110,7 @@ BO_ 282 Steering_2: 8 XXX
|
||||
BO_ 312 Brake_Pressure_L_R: 8 XXX
|
||||
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
|
||||
SG_ Steering_Angle : 16|16@1- (-0.1,0) [-3276.8|3276.7] "" XXX
|
||||
SG_ Brake_1 : 48|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ Brake_2 : 56|8@1+ (1,0) [0|255] "" XXX
|
||||
|
||||
@@ -158,6 +159,7 @@ BO_ 544 ES_Brake: 8 XXX
|
||||
BO_ 577 Cruise_Status: 8 XXX
|
||||
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
|
||||
SG_ Clutch_Depressed : 47|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ Cruise_Set_Speed : 51|12@0+ (1,0) [0|120] "" XXX
|
||||
SG_ Cruise_On : 54|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ Cruise_Activated : 55|1@1+ (1,0) [0|1] "" XXX
|
||||
@@ -211,8 +213,8 @@ BO_ 801 ES_DashStatus: 8 XXX
|
||||
SG_ Signal4 : 31|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ Conventional_Cruise : 32|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ Signal5 : 33|2@1+ (1,0) [0|3] "" XXX
|
||||
SG_ Cruise_Disengaged : 35|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ Cruise_Activated : 36|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ Cruise_Disengaged_Dash : 35|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ Cruise_Activated_Dash : 36|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ Signal6 : 37|3@1+ (1,0) [0|1] "" XXX
|
||||
SG_ Cruise_Set_Speed : 40|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ Cruise_Fault : 48|1@1+ (1,0) [0|1] "" XXX
|
||||
@@ -283,6 +285,7 @@ CM_ SG_ 544 Cruise_Brake_Lights "1 = switch on brake lights";
|
||||
CM_ SG_ 544 Brake_Pressure "Winds down after cruise disabled. Also can be non-zero when likely preparing for AEB";
|
||||
CM_ SG_ 544 Signal3 "Usually goes to 2 if AEB_Status is 4";
|
||||
CM_ SG_ 544 AEB_Status "Occasionally is 4 instead of 8 while Brake_Pressure is non-zero, unsure why";
|
||||
CM_ SG_ 801 Cruise_Activated_Dash "Falls during user gas or standstill. This is likely only a UI signal to the dash to show if ACC is actually actuating";
|
||||
CM_ SG_ 801 PCB_Off "Pre-Collision Braking off";
|
||||
CM_ SG_ 801 Brake_Lights "Driver or Cruise brake on";
|
||||
CM_ SG_ 801 Cruise_State "0 = Normal, 1 = Hold+User Brake, 2 = Ready, 3 = Hold";
|
||||
|
||||
@@ -3,7 +3,7 @@ CM_ "IMPORT _subaru_preglobal_2015.dbc";
|
||||
BO_ 355 ES_DashStatus: 8 XXX
|
||||
SG_ Not_Ready_Startup : 4|2@1+ (1,0) [0|3] "" XXX
|
||||
SG_ Cruise_On : 16|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ Cruise_Activated : 17|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ Cruise_Activated_Dash : 17|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ Cruise_Set_Speed : 24|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ COUNTER : 40|3@1+ (1,0) [0|7] "" XXX
|
||||
SG_ Brake : 43|1@1+ (1,0) [0|1] "" XXX
|
||||
|
||||
@@ -5,7 +5,7 @@ BO_ 358 ES_DashStatus: 8 XXX
|
||||
SG_ Seatbelt_Disengage : 12|2@1+ (1,0) [0|3] "" XXX
|
||||
SG_ Disengage_Alert : 14|2@1+ (1,0) [0|3] "" XXX
|
||||
SG_ Cruise_On : 16|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ Cruise_Activated : 17|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ Cruise_Activated_Dash : 17|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ Signal1 : 18|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ WHEELS_MOVING_2015 : 19|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ Driver_Input : 20|1@1+ (1,0) [0|1] "" XXX
|
||||
|
||||
@@ -5,7 +5,7 @@ BO_ 358 ES_DashStatus: 8 XXX
|
||||
SG_ Seatbelt_Disengage : 12|2@1+ (1,0) [0|3] "" XXX
|
||||
SG_ Disengage_Alert : 14|2@1+ (1,0) [0|3] "" XXX
|
||||
SG_ Cruise_On : 16|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ Cruise_Activated : 17|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ Cruise_Activated_Dash : 17|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ Signal1 : 18|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ WHEELS_MOVING_2015 : 19|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ Driver_Input : 20|1@1+ (1,0) [0|1] "" XXX
|
||||
|
||||
@@ -23,8 +23,9 @@ BO_ 147 IMPRECISE_SPEED_INFORMATION: 8 XXX
|
||||
|
||||
BO_ 161 STEER_AND_AP_STALK: 8 XXX
|
||||
SG_ CRC : 7|8@0+ (1,0) [0|255] "" XXX
|
||||
SG_ STEERING_ANGLE : 15|16@0+ (0.05,0) [0|65535] "degs" XXX
|
||||
SG_ STEERING_TORQUE : 31|16@0+ (1,0) [0|65535] "??" XXX
|
||||
SG_ STEERING_ANGLE : 13|13@0+ (0.05,0) [0|65535] "degs" XXX
|
||||
SG_ STEERING_DIRECTION : 16|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ STEERING_TORQUE : 29|14@0+ (1,0) [0|65535] "??" XXX
|
||||
SG_ AP_REDUCE_DISTANCE_COMMAND : 44|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ AP_INCREASE_DISTANCE_COMMAND : 45|1@0+ (1,0) [0|1] "AUTOPILOT_STALK" XXX
|
||||
SG_ AP_CANCEL_COMMAND : 46|1@0+ (1,0) [0|1] "" XXX
|
||||
|
||||
@@ -37,9 +37,9 @@
|
||||
|
||||
#define MSG_SUBARU_ES_UDS_Request 0x787U
|
||||
|
||||
#define MSG_SUBARU_ES_HighBeamAssist 0x121U
|
||||
#define MSG_SUBARU_ES_STATIC_1 0x22aU
|
||||
#define MSG_SUBARU_ES_STATIC_2 0x325U
|
||||
#define MSG_SUBARU_ES_HighBeamAssist 0x22AU
|
||||
#define MSG_SUBARU_ES_STATIC_1 0x325U
|
||||
#define MSG_SUBARU_ES_STATIC_2 0x121U
|
||||
|
||||
#define SUBARU_MAIN_BUS 0U
|
||||
#define SUBARU_ALT_BUS 1U
|
||||
@@ -105,11 +105,6 @@ static void subaru_rx_hook(const CANPacket_t *msg) {
|
||||
torque_driver_new = ((GET_BYTES(msg, 0, 4) >> 16) & 0x7FFU);
|
||||
torque_driver_new = -1 * to_signed(torque_driver_new, 11);
|
||||
update_sample(&torque_driver, torque_driver_new);
|
||||
|
||||
int angle_meas_new = (GET_BYTES(msg, 4, 2) & 0xFFFFU);
|
||||
// convert Steering_Torque -> Steering_Angle to centidegrees, to match the ES_LKAS_ANGLE angle request units
|
||||
angle_meas_new = ROUND(to_signed(angle_meas_new, 16) * -2.17);
|
||||
update_sample(&angle_meas, angle_meas_new);
|
||||
}
|
||||
|
||||
if ((msg->addr == MSG_SUBARU_ES_LKAS_State) && (msg->bus == SUBARU_CAM_BUS)) {
|
||||
|
||||
@@ -209,9 +209,9 @@ static bool toyota_tx_hook(const CANPacket_t *msg) {
|
||||
|
||||
// the EPS faults when the steering angle rate is above a certain threshold for too long. to prevent this,
|
||||
// we allow setting STEER_REQUEST bit to 0 while maintaining the requested torque value for a single frame
|
||||
.min_valid_request_frames = 18,
|
||||
.min_valid_request_frames = 17,
|
||||
.max_invalid_request_frames = 1,
|
||||
.min_valid_request_rt_interval = 171000, // 171ms; a ~10% buffer on cutting every 19 frames
|
||||
.min_valid_request_rt_interval = 162000, // 162ms; a ~10% buffer on cutting every 18 frames
|
||||
.has_steer_req_tolerance = true,
|
||||
};
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
2.6 X (Cppcheck)
|
||||
2.7 X (Addon)
|
||||
3.1 X (Addon)
|
||||
3.2 X (Addon)
|
||||
3.2
|
||||
4.1 X (Addon)
|
||||
4.2 X (Addon)
|
||||
5.1 X (Addon)
|
||||
|
||||
@@ -15,7 +15,7 @@ fi
|
||||
|
||||
cd $CPPCHECK_DIR
|
||||
|
||||
VERS="2.18.3"
|
||||
VERS="2.19.1"
|
||||
if [ "$(git describe --tags --always)" != "$VERS" ]; then
|
||||
git fetch --all --tags --force
|
||||
git checkout $VERS
|
||||
|
||||
@@ -37,7 +37,7 @@ cppcheck() {
|
||||
|
||||
OPENDBC_ROOT=${OPENDBC_ROOT:-$BASEDIR}
|
||||
$CPPCHECK_DIR/cppcheck --inline-suppr -I $OPENDBC_ROOT \
|
||||
-I "$(gcc -print-file-name=include)" --suppress=*:/usr/lib/gcc/* --suppress=*:*/usr/lib/clang/* \
|
||||
--suppress=missingIncludeSystem \
|
||||
--suppressions-list=$DIR/suppressions.txt \
|
||||
--error-exitcode=2 --check-level=exhaustive --safety \
|
||||
--platform=arm32-wchar_t4 $COMMON_DEFINES --checkers-report=$CHECKLIST.tmp \
|
||||
|
||||
@@ -25,9 +25,9 @@ class SubaruMsg(enum.IntEnum):
|
||||
ES_LKAS_State = 0x322
|
||||
ES_Infotainment = 0x323
|
||||
ES_UDS_Request = 0x787
|
||||
ES_HighBeamAssist = 0x121
|
||||
ES_STATIC_1 = 0x22a
|
||||
ES_STATIC_2 = 0x325
|
||||
ES_HighBeamAssist = 0x22A
|
||||
ES_STATIC_1 = 0x325
|
||||
ES_STATIC_2 = 0x121
|
||||
|
||||
|
||||
SUBARU_MAIN_BUS = 0
|
||||
@@ -95,10 +95,6 @@ class TestSubaruSafetyBase(common.CarSafetyTest):
|
||||
values = {s: speed for s in ["FR", "FL", "RR", "RL"]}
|
||||
return self.packer.make_can_msg_safety("Wheel_Speeds", self.ALT_MAIN_BUS, values)
|
||||
|
||||
def _angle_meas_msg(self, angle):
|
||||
values = {"Steering_Angle": angle}
|
||||
return self.packer.make_can_msg_safety("Steering_Torque", 0, values)
|
||||
|
||||
def _user_brake_msg(self, brake):
|
||||
values = {"Brake": brake}
|
||||
return self.packer.make_can_msg_safety("Brake_Status", self.ALT_MAIN_BUS, values)
|
||||
|
||||
@@ -178,7 +178,7 @@ class TestToyotaSafetyTorque(TestToyotaSafetyBase, common.MotorTorqueSteeringSaf
|
||||
TORQUE_MEAS_TOLERANCE = 1 # toyota safety adds one to be conservative for rounding
|
||||
|
||||
# Safety around steering req bit
|
||||
MIN_VALID_STEERING_FRAMES = 18
|
||||
MIN_VALID_STEERING_FRAMES = 17
|
||||
MAX_INVALID_STEERING_FRAMES = 1
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -66,6 +66,16 @@
|
||||
],
|
||||
"package": "All"
|
||||
},
|
||||
"Acura TLX 2025": {
|
||||
"platform": "ACURA_TLX_2G_MMR",
|
||||
"make": "Acura",
|
||||
"brand": "honda",
|
||||
"model": "TLX",
|
||||
"year": [
|
||||
"2025"
|
||||
],
|
||||
"package": "All"
|
||||
},
|
||||
"Audi A3 2014-19": {
|
||||
"platform": "AUDI_A3_MK3",
|
||||
"make": "Audi",
|
||||
@@ -244,7 +254,7 @@
|
||||
"year": [
|
||||
"2017"
|
||||
],
|
||||
"package": "Adaptive Cruise Control (ACC)"
|
||||
"package": "No Adaptive Cruise Control (Non-ACC)"
|
||||
},
|
||||
"Chevrolet Bolt EV Non-ACC 2018-21": {
|
||||
"platform": "CHEVROLET_BOLT_NON_ACC_1ST_GEN",
|
||||
@@ -257,7 +267,7 @@
|
||||
"2020",
|
||||
"2021"
|
||||
],
|
||||
"package": "Adaptive Cruise Control (ACC)"
|
||||
"package": "No Adaptive Cruise Control (Non-ACC)"
|
||||
},
|
||||
"Chevrolet Equinox 2019-22": {
|
||||
"platform": "CHEVROLET_EQUINOX",
|
||||
@@ -287,7 +297,7 @@
|
||||
"2022",
|
||||
"2023"
|
||||
],
|
||||
"package": "Adaptive Cruise Control (ACC)"
|
||||
"package": "No Adaptive Cruise Control (Non-ACC)"
|
||||
},
|
||||
"Chevrolet Silverado 1500 2020-21": {
|
||||
"platform": "CHEVROLET_SILVERADO",
|
||||
@@ -1300,6 +1310,17 @@
|
||||
],
|
||||
"package": "All"
|
||||
},
|
||||
"Honda Odyssey (Taiwan) 2018-19": {
|
||||
"platform": "HONDA_ODYSSEY_TWN",
|
||||
"make": "Honda",
|
||||
"brand": "honda",
|
||||
"model": "Odyssey (Taiwan)",
|
||||
"year": [
|
||||
"2018",
|
||||
"2019"
|
||||
],
|
||||
"package": "Honda Sensing"
|
||||
},
|
||||
"Honda Passport 2019-25": {
|
||||
"platform": "HONDA_PILOT",
|
||||
"make": "Honda",
|
||||
|
||||
@@ -55,6 +55,7 @@ FW_VERSIONS_EXT = {
|
||||
CAR.KIA_FORTE_2019_NON_SCC: {
|
||||
(Ecu.eps, 0x7D4, None): [
|
||||
b'\xf1\x00BD MDPS C 1.00 1.04 56310/M6000 4BDDC104',
|
||||
b'\xf1\x00BD MDPS C 1.00 1.05 56310/M6000 4BDDC105',
|
||||
],
|
||||
(Ecu.fwdCamera, 0x7C4, None): [
|
||||
b'\xf1\x00BD LKAS AT USA LHD 1.00 1.02 95740-M6000 J31',
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
|
||||
"""
|
||||
Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
|
||||
|
||||
This file is part of sunnypilot and is licensed under the MIT License.
|
||||
See the LICENSE.md file in the root directory for more details.
|
||||
"""
|
||||
|
||||
from enum import StrEnum
|
||||
|
||||
from opendbc.car import Bus, structs
|
||||
from opendbc.can.parser import CANParser
|
||||
from opendbc.sunnypilot.car.mazda.values import BUTTONS
|
||||
|
||||
|
||||
class CarStateExt:
|
||||
def __init__(self, CP, CP_SP):
|
||||
self.CP = CP
|
||||
self.CP_SP = CP_SP
|
||||
|
||||
self.button_events = []
|
||||
self.button_states = {button.event_type: False for button in BUTTONS}
|
||||
|
||||
def update(self, ret: structs.CarState, ret_sp: structs.CarStateSP, can_parsers: dict[StrEnum, CANParser]):
|
||||
cp = can_parsers[Bus.pt]
|
||||
|
||||
button_events = []
|
||||
for button in BUTTONS:
|
||||
state = (cp.vl[button.can_addr][button.can_msg] in button.values)
|
||||
if self.button_states[button.event_type] != state:
|
||||
event = structs.CarState.ButtonEvent.new_message()
|
||||
event.type = button.event_type
|
||||
event.pressed = state
|
||||
button_events.append(event)
|
||||
self.button_states[button.event_type] = state
|
||||
self.button_events = button_events
|
||||
@@ -1,20 +0,0 @@
|
||||
"""
|
||||
Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
|
||||
|
||||
This file is part of sunnypilot and is licensed under the MIT License.
|
||||
See the LICENSE.md file in the root directory for more details.
|
||||
"""
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
from opendbc.car import structs
|
||||
|
||||
ButtonType = structs.CarState.ButtonEvent.Type
|
||||
Button = namedtuple('Button', ['event_type', 'can_addr', 'can_msg', 'values'])
|
||||
|
||||
BUTTONS = [
|
||||
Button(ButtonType.accelCruise, "CRZ_BTNS", "SET_P", [1]),
|
||||
Button(ButtonType.decelCruise, "CRZ_BTNS", "SET_M", [1]),
|
||||
Button(ButtonType.cancel, "CRZ_BTNS", "CAN_OFF", [1]),
|
||||
Button(ButtonType.resumeCruise, "CRZ_BTNS", "RES", [1]),
|
||||
]
|
||||
@@ -1,6 +1,7 @@
|
||||
import re
|
||||
import json
|
||||
import os
|
||||
from natsort import natsorted
|
||||
import unicodedata
|
||||
|
||||
from opendbc.car.common.basedir import BASEDIR
|
||||
from opendbc.car.docs import get_all_footnotes, get_params_for_docs
|
||||
@@ -15,6 +16,12 @@ def get_car_list() -> dict[str, dict[str, list[str] | str]]:
|
||||
return sorted_list
|
||||
|
||||
|
||||
def _natural_sort_key(s):
|
||||
# NFKD normalization ensures accented characters sort with their base letter (e.g., Š sorts with S)
|
||||
normalized = unicodedata.normalize('NFKD', s)
|
||||
return [int(t) if t.isdigit() else t.lower() for t in re.split(r'(\d+)', normalized) if t]
|
||||
|
||||
|
||||
def build_sorted_car_list(platforms, footnotes) -> dict[str, dict[str, list[str] | str]]:
|
||||
cars: dict[str, dict[str, list[str] | str]] = {}
|
||||
for model, platform in platforms.items():
|
||||
@@ -49,7 +56,7 @@ def build_sorted_car_list(platforms, footnotes) -> dict[str, dict[str, list[str]
|
||||
}
|
||||
|
||||
# Sort cars by make and model + year
|
||||
sorted_cars = natsorted(cars.keys(), key=lambda car: car.lower())
|
||||
sorted_cars = sorted(cars.keys(), key=lambda car: _natural_sort_key(car))
|
||||
sorted_car_list = {car: cars[car] for car in sorted_cars}
|
||||
return sorted_car_list
|
||||
|
||||
|
||||
@@ -44,7 +44,6 @@ testing = [
|
||||
]
|
||||
docs = [
|
||||
"Jinja2",
|
||||
"natsort",
|
||||
]
|
||||
examples = [
|
||||
"inputs",
|
||||
|
||||
Reference in New Issue
Block a user