mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-09-15 02:13:43 +08:00
Compare commits
148 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c590c39362 | |||
| 1b0ae07a0c | |||
| a564824c85 | |||
| 78635eee88 | |||
| 97c7eacbf4 | |||
| 4a204b8a22 | |||
| ae658b82d7 | |||
| 11aeebf452 | |||
| f6be0110b8 | |||
| 8981993def | |||
| 209cbaed01 | |||
| 028c3691f6 | |||
| de64b99740 | |||
| 0e1de37281 | |||
| 5a309daee6 | |||
| 520649b893 | |||
| 18abe218d9 | |||
| cca3be3a96 | |||
| 282a8b093d | |||
| 1e7fc15a04 | |||
| e999839a57 | |||
| 1bfecbc9c2 | |||
| dcd382ffb8 | |||
| 09d165a85b | |||
| 4c4964a740 | |||
| 225ce45d31 | |||
| 92214b69d8 | |||
| f3ed577870 | |||
| 49e58a2532 | |||
| ae901d1562 | |||
| 85d2653fda | |||
| 0f4828df82 | |||
| dc0fd4ca96 | |||
| 90adc18032 | |||
| db65937fc7 | |||
| 8ebe9b69af | |||
| 4c40be8b1f | |||
| 082ea8119b | |||
| 1465e38c7b | |||
| ecee67dd64 | |||
| ea6178e53e | |||
| 01a0ad496d | |||
| b64d5a0fa4 | |||
| 005c6aed95 | |||
| 2fa66d6f4d | |||
| d5a873ed86 | |||
| 563ae65443 | |||
| 2efe78a4ef | |||
| 569a9216db | |||
| 629cfd845f | |||
| 2892dc05c8 | |||
| 632b416f2a | |||
| 5f3821c1f9 | |||
| 55b7529ca4 | |||
| c248f307f8 | |||
| bdb83b6be1 | |||
| c55f40e77d | |||
| ddf63701e8 | |||
| 28098bb7c4 | |||
| 60e056cc0a | |||
| fb743d313e | |||
| 4441671227 | |||
| 1f8941367d | |||
| 784e1d6658 | |||
| cb94d3b055 | |||
| 94f93a9f26 | |||
| 747460363f | |||
| b32c6dafee | |||
| bffb2fb6fa | |||
| 688b694266 | |||
| ec8f036850 | |||
| 4f44d6e643 | |||
| 1be13fdc55 | |||
| 810a2d9448 | |||
| c9dbf97649 | |||
| 1bb4ca2547 | |||
| 2c04a27a2a | |||
| b7f8dd11a5 | |||
| 70c0592e84 | |||
| 572c03dbac | |||
| fa498221da | |||
| 67238d5045 | |||
| 994170ddb5 | |||
| 3c28188d7a | |||
| 4ccd17903b | |||
| 0e1b573f89 | |||
| 10580aca92 | |||
| 6b13175338 | |||
| d0171084b5 | |||
| 2bfdd0d61d | |||
| ea53111afc | |||
| 0739d4ac2d | |||
| 698e0ca00f | |||
| 8dca43881a | |||
| a885111c0c | |||
| bd73664f4c | |||
| 608c16007e | |||
| 275abc1eb5 | |||
| ff34b8af76 | |||
| ff4d1923f0 | |||
| 3a91ae08a9 | |||
| 03e9777c3f | |||
| 1033d3d80e | |||
| 1f1efec4c9 | |||
| f0f04d4b5b | |||
| 2b7707ecf6 | |||
| ef870d5533 | |||
| a5044302a2 | |||
| 6a4f685d04 | |||
| 355499a8de | |||
| 67fd6c80dd | |||
| c990515eaf | |||
| 76e91da3ad | |||
| 9fcac06297 | |||
| 3e2549f2b8 | |||
| 63961dec45 | |||
| 7a19a11001 | |||
| 93f7925c4d | |||
| a2c5fca787 | |||
| bb06468ead | |||
| 1d8dc8a69a | |||
| a254a05df0 | |||
| 2aa7648bb8 | |||
| b309bf4173 | |||
| a3fcde2ae8 | |||
| f8ff156869 | |||
| 375dfe16a8 | |||
| b976135d2f | |||
| f40f7f9ece | |||
| ea6677c464 | |||
| 8258257658 | |||
| f5d67b5eee | |||
| 8ee3c7b485 | |||
| 8450f9f333 | |||
| 4cd76f4966 | |||
| ec254074d1 | |||
| 8059106cae | |||
| 23b4aaf2a5 | |||
| 5359f6d354 | |||
| a70e4c3074 | |||
| 7a2f2ddf32 | |||
| 2dc0f97c93 | |||
| 15fcbf24f1 | |||
| e89c6b3b88 | |||
| c4a7f25b62 | |||
| 1d74a97ba6 | |||
| aea467ff02 | |||
| b501ad4d51 |
@@ -29,21 +29,21 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
target: /^(?!master-tici$).*/
|
target: /^(?!master$).*/
|
||||||
exclude: /sunnypilot:.*/
|
exclude: /sunnypilot:.*/
|
||||||
change-to: ${{ github.base_ref }}
|
change-to: ${{ github.base_ref }}
|
||||||
already-exists-action: close_this
|
already-exists-action: close_this
|
||||||
already-exists-comment: "Your PR should be made against the `master-tici` branch"
|
already-exists-comment: "Your PR should be made against the `master` branch"
|
||||||
|
|
||||||
update-pr-labels:
|
update-pr-labels:
|
||||||
name: Update fork's PR Labels
|
name: Update fork's PR Labels
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: (github.event.pull_request.head.repo.fork && (contains(github.event_name, 'pull_request') && github.event.action == 'synchronize'))
|
if: (github.event.pull_request.head.repo.fork && (contains(github.event_name, 'pull_request') && github.event.action == 'synchronize'))
|
||||||
env:
|
env:
|
||||||
PR_LABEL: 'dev-c3'
|
PR_LABEL: 'dev'
|
||||||
TRUST_FORK_PR_LABEL: 'trust-fork-pr'
|
TRUST_FORK_PR_LABEL: 'trust-fork-pr'
|
||||||
steps:
|
steps:
|
||||||
- name: Check if PR has dev-c3 label
|
- name: Check if PR has dev label
|
||||||
id: check-labels
|
id: check-labels
|
||||||
uses: actions/github-script@v7
|
uses: actions/github-script@v7
|
||||||
with:
|
with:
|
||||||
@@ -62,11 +62,11 @@ jobs:
|
|||||||
console.log(`PR #${prNumber} has ${process.env.PR_LABEL} label: ${hasDevC3Label}`);
|
console.log(`PR #${prNumber} has ${process.env.PR_LABEL} label: ${hasDevC3Label}`);
|
||||||
console.log(`PR #${prNumber} has ${process.env.TRUST_FORK_PR_LABEL} label: ${hasTrustLabel}`);
|
console.log(`PR #${prNumber} has ${process.env.TRUST_FORK_PR_LABEL} label: ${hasTrustLabel}`);
|
||||||
|
|
||||||
core.setOutput('has-dev-c3', hasDevC3Label ? 'true' : 'false');
|
core.setOutput('has-dev', hasDevC3Label ? 'true' : 'false');
|
||||||
core.setOutput('has-trust', hasTrustLabel ? 'true' : 'false');
|
core.setOutput('has-trust', hasTrustLabel ? 'true' : 'false');
|
||||||
|
|
||||||
- name: Remove trust-fork-pr label if present
|
- name: Remove trust-fork-pr label if present
|
||||||
if: steps.check-labels.outputs.has-dev-c3 == 'true' && steps.check-labels.outputs.has-trust == 'true'
|
if: steps.check-labels.outputs.has-dev == 'true' && steps.check-labels.outputs.has-trust == 'true'
|
||||||
uses: actions/github-script@v7
|
uses: actions/github-script@v7
|
||||||
with:
|
with:
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
BASE_IMAGE: sunnypilot-tici-base
|
BASE_IMAGE: sunnypilot-base
|
||||||
DOCKER_REGISTRY: ghcr.io/sunnypilot
|
DOCKER_REGISTRY: ghcr.io/sunnypilot
|
||||||
RUN: docker run --shm-size 2G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $DOCKER_REGISTRY/$BASE_IMAGE:latest /bin/bash -c
|
RUN: docker run --shm-size 2G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $DOCKER_REGISTRY/$BASE_IMAGE:latest /bin/bash -c
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ name: cereal validation
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master-tici
|
- master
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- 'cereal/**'
|
- 'cereal/**'
|
||||||
@@ -16,7 +16,7 @@ on:
|
|||||||
type: string
|
type: string
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: cereal-validation-ci-run-${{ inputs.run_number }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master-tici' && github.run_id || github.head_ref || github.ref }}-${{ github.workflow }}-${{ github.event_name }}
|
group: cereal-validation-ci-run-${{ inputs.run_number }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.run_id || github.head_ref || github.ref }}-${{ github.workflow }}-${{ github.event_name }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
env:
|
env:
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix: ${{fromJSON(needs.setup.outputs.ci_runs)}}
|
matrix: ${{fromJSON(needs.setup.outputs.ci_runs)}}
|
||||||
uses: sunnypilot/sunnypilot/.github/workflows/ci_weekly_run.yaml@master-tici
|
uses: sunnypilot/sunnypilot/.github/workflows/ci_weekly_run.yaml@master
|
||||||
with:
|
with:
|
||||||
run_number: ${{ matrix.run_number }}
|
run_number: ${{ matrix.run_number }}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,6 @@ concurrency:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
selfdrive_tests:
|
selfdrive_tests:
|
||||||
uses: sunnypilot/sunnypilot/.github/workflows/selfdrive_tests.yaml@master-tici
|
uses: sunnypilot/sunnypilot/.github/workflows/selfdrive_tests.yaml@master
|
||||||
with:
|
with:
|
||||||
run_number: ${{ inputs.run_number }}
|
run_number: ${{ inputs.run_number }}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ runs:
|
|||||||
scons -j$(nproc) --cache-populate"
|
scons -j$(nproc) --cache-populate"
|
||||||
- name: Save scons cache
|
- name: Save scons cache
|
||||||
uses: actions/cache/save@v4
|
uses: actions/cache/save@v4
|
||||||
if: github.ref == 'refs/heads/master-tici'
|
if: github.ref == 'refs/heads/master'
|
||||||
with:
|
with:
|
||||||
path: .ci_cache/scons_cache
|
path: .ci_cache/scons_cache
|
||||||
key: scons-${{ runner.arch }}-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
key: scons-${{ runner.arch }}-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ name: docs
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master-tici
|
- master
|
||||||
pull_request:
|
pull_request:
|
||||||
workflow_call:
|
workflow_call:
|
||||||
inputs:
|
inputs:
|
||||||
@@ -12,7 +12,7 @@ on:
|
|||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
concurrency:
|
concurrency:
|
||||||
group: docs-tests-ci-run-${{ inputs.run_number }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master-tici' && github.run_id || github.head_ref || github.ref }}-${{ github.workflow }}-${{ github.event_name }}
|
group: docs-tests-ci-run-${{ inputs.run_number }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.run_id || github.head_ref || github.ref }}-${{ github.workflow }}-${{ github.event_name }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -35,13 +35,13 @@ jobs:
|
|||||||
|
|
||||||
# Push to docs.comma.ai
|
# Push to docs.comma.ai
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
if: github.ref == 'refs/heads/master-tici' && github.repository == 'sunnypilot/sunnypilot'
|
if: github.ref == 'refs/heads/master' && github.repository == 'sunnypilot/sunnypilot'
|
||||||
with:
|
with:
|
||||||
path: openpilot-docs
|
path: openpilot-docs
|
||||||
ssh-key: ${{ secrets.OPENPILOT_DOCS_KEY }}
|
ssh-key: ${{ secrets.OPENPILOT_DOCS_KEY }}
|
||||||
repository: sunnypilot/sunnypilot-docs
|
repository: sunnypilot/sunnypilot-docs
|
||||||
- name: Push
|
- name: Push
|
||||||
if: github.ref == 'refs/heads/master-tici' && github.repository == 'sunnypilot/sunnypilot'
|
if: github.ref == 'refs/heads/master' && github.repository == 'sunnypilot/sunnypilot'
|
||||||
run: |
|
run: |
|
||||||
set -x
|
set -x
|
||||||
|
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ jobs:
|
|||||||
if: ${{ github.event_name != 'workflow_dispatch' }}
|
if: ${{ github.event_name != 'workflow_dispatch' }}
|
||||||
uses: lewagon/wait-on-check-action@ccfb013c15c8afb7bf2b7c028fb74dc5a068cccc
|
uses: lewagon/wait-on-check-action@ccfb013c15c8afb7bf2b7c028fb74dc5a068cccc
|
||||||
with:
|
with:
|
||||||
ref: master-tici
|
ref: master
|
||||||
wait-interval: 30
|
wait-interval: 30
|
||||||
running-workflow-name: 'build prebuilt'
|
running-workflow-name: 'build prebuilt'
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
check-regexp: ^((?!.*(build __nightly).*).)*$
|
check-regexp: ^((?!.*(build master-ci).*).)*$
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ jobs:
|
|||||||
contents: write
|
contents: write
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: False
|
|
||||||
steps:
|
steps:
|
||||||
- uses: release-drafter/release-drafter@v6
|
- uses: release-drafter/release-drafter@v6
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
ImageOS: ubuntu24
|
ImageOS: ubuntu24
|
||||||
container:
|
container:
|
||||||
image: ghcr.io/sunnypilot/sunnypilot-tici-base:latest
|
image: ghcr.io/sunnypilot/sunnypilot-base:latest
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: github.repository == 'sunnypilot/sunnypilot'
|
if: github.repository == 'sunnypilot/sunnypilot'
|
||||||
permissions:
|
permissions:
|
||||||
@@ -25,7 +25,7 @@ jobs:
|
|||||||
if: ${{ github.event_name == 'schedule' }}
|
if: ${{ github.event_name == 'schedule' }}
|
||||||
uses: lewagon/wait-on-check-action@ccfb013c15c8afb7bf2b7c028fb74dc5a068cccc
|
uses: lewagon/wait-on-check-action@ccfb013c15c8afb7bf2b7c028fb74dc5a068cccc
|
||||||
with:
|
with:
|
||||||
ref: master-tici
|
ref: master
|
||||||
wait-interval: 30
|
wait-interval: 30
|
||||||
running-workflow-name: 'build __nightly'
|
running-workflow-name: 'build __nightly'
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
BASE_IMAGE: sunnypilot-tici-base
|
BASE_IMAGE: sunnypilot-base
|
||||||
BUILD: release/ci/docker_build_sp.sh base
|
BUILD: release/ci/docker_build_sp.sh base
|
||||||
RUN: docker run --shm-size 2G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e CI=1 -e PYTHONWARNINGS=error -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/bash -c
|
RUN: docker run --shm-size 2G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e CI=1 -e PYTHONWARNINGS=error -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/bash -c
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ jobs:
|
|||||||
title: "[bot] Update translations"
|
title: "[bot] Update translations"
|
||||||
body: "Automatic PR from repo-maintenance -> update_translations"
|
body: "Automatic PR from repo-maintenance -> update_translations"
|
||||||
branch: "update-translations"
|
branch: "update-translations"
|
||||||
base: "master-tici"
|
base: "master"
|
||||||
delete-branch: true
|
delete-branch: true
|
||||||
labels: bot
|
labels: bot
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ jobs:
|
|||||||
name: package_updates
|
name: package_updates
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
image: ghcr.io/sunnypilot/sunnypilot-tici-base:latest
|
image: ghcr.io/sunnypilot/sunnypilot-base:latest
|
||||||
if: github.repository == 'sunnypilot/sunnypilot'
|
if: github.repository == 'sunnypilot/sunnypilot'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -68,7 +68,7 @@ jobs:
|
|||||||
commit-message: Update Python packages
|
commit-message: Update Python packages
|
||||||
title: '[bot] Update Python packages'
|
title: '[bot] Update Python packages'
|
||||||
branch: auto-package-updates
|
branch: auto-package-updates
|
||||||
base: master-tici
|
base: master
|
||||||
delete-branch: true
|
delete-branch: true
|
||||||
body: 'Automatic PR from repo-maintenance -> package_updates'
|
body: 'Automatic PR from repo-maintenance -> package_updates'
|
||||||
labels: bot
|
labels: bot
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ name: selfdrive
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master-tici
|
- master
|
||||||
pull_request:
|
pull_request:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
workflow_call:
|
workflow_call:
|
||||||
@@ -14,12 +14,12 @@ on:
|
|||||||
type: string
|
type: string
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: selfdrive-tests-ci-run-${{ inputs.run_number }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master-tici' && github.run_id || github.head_ref || github.ref }}-${{ github.workflow }}-${{ github.event_name }}
|
group: selfdrive-tests-ci-run-${{ inputs.run_number }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.run_id || github.head_ref || github.ref }}-${{ github.workflow }}-${{ github.event_name }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
env:
|
env:
|
||||||
PYTHONWARNINGS: error
|
PYTHONWARNINGS: error
|
||||||
BASE_IMAGE: sunnypilot-tici-base
|
BASE_IMAGE: sunnypilot-base
|
||||||
AZURE_TOKEN: ${{ secrets.AZURE_COMMADATACI_OPENPILOTCI_TOKEN }}
|
AZURE_TOKEN: ${{ secrets.AZURE_COMMADATACI_OPENPILOTCI_TOKEN }}
|
||||||
|
|
||||||
DOCKER_LOGIN: docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }}
|
DOCKER_LOGIN: docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -68,10 +68,10 @@ jobs:
|
|||||||
if: github.repository == 'sunnypilot/sunnypilot'
|
if: github.repository == 'sunnypilot/sunnypilot'
|
||||||
timeout-minutes: 3
|
timeout-minutes: 3
|
||||||
run: |
|
run: |
|
||||||
if [ "${{ github.ref }}" != "refs/heads/master-tici" ]; then
|
if [ "${{ github.ref }}" != "refs/heads/master" ]; then
|
||||||
git fetch origin master-tici:refs/remotes/origin/master-tici
|
git fetch origin master:refs/remotes/origin/master
|
||||||
|
|
||||||
SUBMODULE_PATHS=$(git diff origin/master-tici HEAD --name-only | grep -E '^[^/]+$' | while read path; do
|
SUBMODULE_PATHS=$(git diff origin/master HEAD --name-only | grep -E '^[^/]+$' | while read path; do
|
||||||
if git ls-files --stage "$path" | grep -q "^160000"; then
|
if git ls-files --stage "$path" | grep -q "^160000"; then
|
||||||
echo "$path"
|
echo "$path"
|
||||||
fi
|
fi
|
||||||
@@ -97,7 +97,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Setup docker push
|
- name: Setup docker push
|
||||||
if: github.ref == 'refs/heads/master-tici' && github.event_name != 'pull_request' && github.repository == 'sunnypilot/sunnypilot'
|
if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'sunnypilot/sunnypilot'
|
||||||
run: |
|
run: |
|
||||||
echo "PUSH_IMAGE=true" >> "$GITHUB_ENV"
|
echo "PUSH_IMAGE=true" >> "$GITHUB_ENV"
|
||||||
$DOCKER_LOGIN
|
$DOCKER_LOGIN
|
||||||
@@ -107,7 +107,6 @@ jobs:
|
|||||||
|
|
||||||
build_mac:
|
build_mac:
|
||||||
name: build macOS
|
name: build macOS
|
||||||
if: false # temp disable since homebrew install is getting stuck
|
|
||||||
runs-on: ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-macos-8x14' || 'macos-latest' }}
|
runs-on: ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-macos-8x14' || 'macos-latest' }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -116,7 +115,9 @@ jobs:
|
|||||||
- run: echo "CACHE_COMMIT_DATE=$(git log -1 --pretty='format:%cd' --date=format:'%Y-%m-%d-%H:%M')" >> $GITHUB_ENV
|
- run: echo "CACHE_COMMIT_DATE=$(git log -1 --pretty='format:%cd' --date=format:'%Y-%m-%d-%H:%M')" >> $GITHUB_ENV
|
||||||
- name: Homebrew cache
|
- name: Homebrew cache
|
||||||
uses: ./.github/workflows/auto-cache
|
uses: ./.github/workflows/auto-cache
|
||||||
|
if: false # disabling the cache for now because it is breaking macos builds...
|
||||||
with:
|
with:
|
||||||
|
save: false # No need save here if we manually save it later conditionally
|
||||||
path: ~/Library/Caches/Homebrew
|
path: ~/Library/Caches/Homebrew
|
||||||
key: brew-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
key: brew-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
@@ -125,11 +126,11 @@ jobs:
|
|||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: ./tools/mac_setup.sh
|
run: ./tools/mac_setup.sh
|
||||||
env:
|
env:
|
||||||
# package install has DeprecationWarnings
|
PYTHONWARNINGS: default # package install has DeprecationWarnings
|
||||||
PYTHONWARNINGS: default
|
HOMEBREW_DISPLAY_INSTALL_TIMES: 1
|
||||||
- name: Save Homebrew cache
|
- name: Save Homebrew cache
|
||||||
uses: actions/cache/save@v4
|
uses: actions/cache/save@v4
|
||||||
if: github.ref == 'refs/heads/master-tici'
|
if: github.ref == 'refs/heads/master'
|
||||||
with:
|
with:
|
||||||
path: ~/Library/Caches/Homebrew
|
path: ~/Library/Caches/Homebrew
|
||||||
key: brew-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
key: brew-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
||||||
@@ -137,6 +138,7 @@ jobs:
|
|||||||
- name: Getting scons cache
|
- name: Getting scons cache
|
||||||
uses: ./.github/workflows/auto-cache
|
uses: ./.github/workflows/auto-cache
|
||||||
with:
|
with:
|
||||||
|
save: false # No need save here if we manually save it later conditionally
|
||||||
path: /tmp/scons_cache
|
path: /tmp/scons_cache
|
||||||
key: scons-${{ runner.arch }}-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
key: scons-${{ runner.arch }}-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
@@ -146,7 +148,7 @@ jobs:
|
|||||||
run: . .venv/bin/activate && scons -j$(nproc)
|
run: . .venv/bin/activate && scons -j$(nproc)
|
||||||
- name: Save scons cache
|
- name: Save scons cache
|
||||||
uses: actions/cache/save@v4
|
uses: actions/cache/save@v4
|
||||||
if: github.ref == 'refs/heads/master-tici'
|
if: github.ref == 'refs/heads/master'
|
||||||
with:
|
with:
|
||||||
path: /tmp/scons_cache
|
path: /tmp/scons_cache
|
||||||
key: scons-${{ runner.arch }}-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
key: scons-${{ runner.arch }}-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
||||||
@@ -305,5 +307,5 @@ jobs:
|
|||||||
- name: Upload Test Report
|
- name: Upload Test Report
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: report-${{ inputs.run_number || '1' }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master-tici' && 'master-tici' || github.event.number }}
|
name: report-${{ inputs.run_number || '1' }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && 'master' || github.event.number }}
|
||||||
path: selfdrive/ui/tests/test_ui/report_1/screenshots
|
path: selfdrive/ui/tests/test_ui/report_1/screenshots
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ on:
|
|||||||
upstream_branch:
|
upstream_branch:
|
||||||
description: 'Upstream branch to build from'
|
description: 'Upstream branch to build from'
|
||||||
required: true
|
required: true
|
||||||
default: 'master-tici'
|
default: 'master'
|
||||||
type: string
|
type: string
|
||||||
custom_name:
|
custom_name:
|
||||||
description: 'Custom name for the model (no date, only name)'
|
description: 'Custom name for the model (no date, only name)'
|
||||||
@@ -35,7 +35,7 @@ on:
|
|||||||
upstream_branch:
|
upstream_branch:
|
||||||
description: 'Upstream branch to build from'
|
description: 'Upstream branch to build from'
|
||||||
required: true
|
required: true
|
||||||
default: 'master-tici'
|
default: 'master'
|
||||||
type: string
|
type: string
|
||||||
custom_name:
|
custom_name:
|
||||||
description: 'Custom name for the model (no date, only name)'
|
description: 'Custom name for the model (no date, only name)'
|
||||||
|
|||||||
@@ -8,14 +8,14 @@ env:
|
|||||||
PUBLIC_REPO_URL: "https://github.com/sunnypilot/sunnypilot"
|
PUBLIC_REPO_URL: "https://github.com/sunnypilot/sunnypilot"
|
||||||
|
|
||||||
# Branch configurations
|
# Branch configurations
|
||||||
STAGING_C3_SOURCE_BRANCH: 'master-tici' # vars.STAGING_C3_SOURCE_BRANCH could be used, set on repo settings.
|
STAGING_SOURCE_BRANCH: 'master'
|
||||||
|
|
||||||
# Runtime configuration
|
# Runtime configuration
|
||||||
SOURCE_BRANCH: "${{ github.head_ref || github.ref_name }}"
|
SOURCE_BRANCH: "${{ github.head_ref || github.ref_name }}"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master-tici ]
|
branches: [ master, master-dev ]
|
||||||
tags: [ 'release/*' ]
|
tags: [ 'release/*' ]
|
||||||
pull_request_target:
|
pull_request_target:
|
||||||
types: [ labeled ]
|
types: [ labeled ]
|
||||||
@@ -138,7 +138,7 @@ jobs:
|
|||||||
# for security. Only caches from the default branch are shared across all builds. This is by design and cannot be overridden.
|
# for security. Only caches from the default branch are shared across all builds. This is by design and cannot be overridden.
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.SOURCE_BRANCH }}
|
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.SOURCE_BRANCH }}
|
||||||
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.STAGING_C3_SOURCE_BRANCH }}
|
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.STAGING_SOURCE_BRANCH }}
|
||||||
scons-${{ runner.os }}-${{ runner.arch }}
|
scons-${{ runner.os }}-${{ runner.arch }}
|
||||||
|
|
||||||
- name: Set environment variables
|
- name: Set environment variables
|
||||||
|
|||||||
+14
-10
@@ -1,31 +1,31 @@
|
|||||||
name: Build dev-c3-new
|
name: Build dev
|
||||||
|
|
||||||
env:
|
env:
|
||||||
DEFAULT_SOURCE_BRANCH: "master-tici"
|
DEFAULT_SOURCE_BRANCH: "master"
|
||||||
DEFAULT_TARGET_BRANCH: "master-dev-c3-new"
|
DEFAULT_TARGET_BRANCH: "master-dev"
|
||||||
PR_LABEL: "dev-c3"
|
PR_LABEL: "dev"
|
||||||
LFS_URL: 'https://gitlab.com/sunnypilot/public/sunnypilot-new-lfs.git/info/lfs'
|
LFS_URL: 'https://gitlab.com/sunnypilot/public/sunnypilot-new-lfs.git/info/lfs'
|
||||||
LFS_PUSH_URL: 'ssh://git@gitlab.com/sunnypilot/public/sunnypilot-new-lfs.git'
|
LFS_PUSH_URL: 'ssh://git@gitlab.com/sunnypilot/public/sunnypilot-new-lfs.git'
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master-tici
|
- master
|
||||||
pull_request_target:
|
pull_request_target:
|
||||||
types: [ labeled ]
|
types: [ labeled ]
|
||||||
branches:
|
branches:
|
||||||
- 'master-tici'
|
- 'master'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
source_branch:
|
source_branch:
|
||||||
description: 'Source branch to reset from'
|
description: 'Source branch to reset from'
|
||||||
required: true
|
required: true
|
||||||
default: 'master-tici'
|
default: 'master'
|
||||||
type: string
|
type: string
|
||||||
target_branch:
|
target_branch:
|
||||||
description: 'Target branch to reset and squash into'
|
description: 'Target branch to reset and squash into'
|
||||||
required: true
|
required: true
|
||||||
default: 'master-dev-c3-new'
|
default: 'master-dev'
|
||||||
type: string
|
type: string
|
||||||
cancel_in_progress:
|
cancel_in_progress:
|
||||||
description: 'Cancel any in-progress runs of this workflow'
|
description: 'Cancel any in-progress runs of this workflow'
|
||||||
@@ -40,7 +40,11 @@ concurrency:
|
|||||||
jobs:
|
jobs:
|
||||||
reset-and-squash:
|
reset-and-squash:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: False
|
if: (
|
||||||
|
(github.event_name == 'workflow_dispatch')
|
||||||
|
|| (github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch))
|
||||||
|
|| (contains(github.event_name, 'pull_request') && ((github.event.action == 'labeled' && (github.event.label.name == 'dev' || github.event.label.name == 'trust-fork-pr') && contains(github.event.pull_request.labels.*.name, 'dev'))))
|
||||||
|
)
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
@@ -51,7 +55,7 @@ jobs:
|
|||||||
uses: ./.github/workflows/wait-for-action # Path to where you place the action
|
uses: ./.github/workflows/wait-for-action # Path to where you place the action
|
||||||
if: (
|
if: (
|
||||||
(github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch))
|
(github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch))
|
||||||
|| (contains(github.event_name, 'pull_request') && ((github.event.action == 'labeled' && (github.event.label.name == 'dev-c3' || github.event.label.name == 'trust-fork-pr') && contains(github.event.pull_request.labels.*.name, 'dev-c3'))))
|
|| (contains(github.event_name, 'pull_request') && ((github.event.action == 'labeled' && (github.event.label.name == 'dev' || github.event.label.name == 'trust-fork-pr') && contains(github.event.pull_request.labels.*.name, 'dev'))))
|
||||||
)
|
)
|
||||||
with:
|
with:
|
||||||
workflow: selfdrive_tests.yaml # The workflow file to monitor
|
workflow: selfdrive_tests.yaml # The workflow file to monitor
|
||||||
@@ -2,19 +2,19 @@ name: "ui preview"
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master-tici
|
- master
|
||||||
pull_request_target:
|
pull_request_target:
|
||||||
types: [assigned, opened, synchronize, reopened, edited]
|
types: [assigned, opened, synchronize, reopened, edited]
|
||||||
branches:
|
branches:
|
||||||
- 'master-tici'
|
- 'master'
|
||||||
paths:
|
paths:
|
||||||
- 'selfdrive/ui/**'
|
- 'selfdrive/ui/**'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
UI_JOB_NAME: "Create UI Report"
|
UI_JOB_NAME: "Create UI Report"
|
||||||
REPORT_NAME: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master-tici' && 'master-tici' || github.event.number }}
|
REPORT_NAME: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && 'master' || github.event.number }}
|
||||||
SHA: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master-tici' && github.sha || github.event.pull_request.head.sha }}
|
SHA: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.sha || github.event.pull_request.head.sha }}
|
||||||
BRANCH_NAME: "openpilot/pr-${{ github.event.number }}"
|
BRANCH_NAME: "openpilot/pr-${{ github.event.number }}"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -55,7 +55,7 @@ jobs:
|
|||||||
name: report-1-${{ env.REPORT_NAME }}
|
name: report-1-${{ env.REPORT_NAME }}
|
||||||
path: ${{ github.workspace }}/pr_ui
|
path: ${{ github.workspace }}/pr_ui
|
||||||
|
|
||||||
- name: Getting master-tici ui
|
- name: Getting master ui
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
repository: sunnypilot/ci-artifacts
|
repository: sunnypilot/ci-artifacts
|
||||||
@@ -63,8 +63,8 @@ jobs:
|
|||||||
path: ${{ github.workspace }}/master_ui
|
path: ${{ github.workspace }}/master_ui
|
||||||
ref: openpilot_master_ui
|
ref: openpilot_master_ui
|
||||||
|
|
||||||
- name: Saving new master-tici ui
|
- name: Saving new master ui
|
||||||
if: github.ref == 'refs/heads/master-tici' && github.event_name == 'push'
|
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
|
||||||
working-directory: ${{ github.workspace }}/master_ui
|
working-directory: ${{ github.workspace }}/master_ui
|
||||||
run: |
|
run: |
|
||||||
git checkout --orphan=new_master_ui
|
git checkout --orphan=new_master_ui
|
||||||
@@ -93,9 +93,9 @@ jobs:
|
|||||||
|
|
||||||
for ((i=0; i<${#A[*]}; i=i+1));
|
for ((i=0; i<${#A[*]}; i=i+1));
|
||||||
do
|
do
|
||||||
# Check if the master-tici file exists
|
# Check if the master file exists
|
||||||
if [ ! -f "${{ github.workspace }}/master_ui/${A[$i]}.png" ]; then
|
if [ ! -f "${{ github.workspace }}/master_ui/${A[$i]}.png" ]; then
|
||||||
# This is a new file in PR UI that doesn't exist in master-tici
|
# This is a new file in PR UI that doesn't exist in master
|
||||||
DIFF="${DIFF}<details open>"
|
DIFF="${DIFF}<details open>"
|
||||||
DIFF="${DIFF}<summary>${A[$i]} : \$\${\\color{cyan}\\text{NEW}}\$\$</summary>"
|
DIFF="${DIFF}<summary>${A[$i]} : \$\${\\color{cyan}\\text{NEW}}\$\$</summary>"
|
||||||
DIFF="${DIFF}<table>"
|
DIFF="${DIFF}<table>"
|
||||||
@@ -118,7 +118,7 @@ jobs:
|
|||||||
DIFF="${DIFF}<table>"
|
DIFF="${DIFF}<table>"
|
||||||
|
|
||||||
DIFF="${DIFF}<tr>"
|
DIFF="${DIFF}<tr>"
|
||||||
DIFF="${DIFF} <td> master-tici <img src=\"https://raw.githubusercontent.com/sunnypilot/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}_master_ref.png\"> </td>"
|
DIFF="${DIFF} <td> master <img src=\"https://raw.githubusercontent.com/sunnypilot/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}_master_ref.png\"> </td>"
|
||||||
DIFF="${DIFF} <td> proposed <img src=\"https://raw.githubusercontent.com/sunnypilot/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}.png\"> </td>"
|
DIFF="${DIFF} <td> proposed <img src=\"https://raw.githubusercontent.com/sunnypilot/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}.png\"> </td>"
|
||||||
DIFF="${DIFF}</tr>"
|
DIFF="${DIFF}</tr>"
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ cereal/services.h
|
|||||||
cereal/gen
|
cereal/gen
|
||||||
cereal/messaging/bridge
|
cereal/messaging/bridge
|
||||||
selfdrive/mapd/default_speeds_by_region.json
|
selfdrive/mapd/default_speeds_by_region.json
|
||||||
system/proclogd/proclogd
|
|
||||||
selfdrive/ui/translations/tmp
|
selfdrive/ui/translations/tmp
|
||||||
selfdrive/test/longitudinal_maneuvers/out
|
selfdrive/test/longitudinal_maneuvers/out
|
||||||
selfdrive/car/tests/cars_dump
|
selfdrive/car/tests/cars_dump
|
||||||
|
|||||||
Vendored
+40
-1
@@ -23,6 +23,11 @@
|
|||||||
"id": "args",
|
"id": "args",
|
||||||
"description": "Arguments to pass to the process",
|
"description": "Arguments to pass to the process",
|
||||||
"type": "promptString"
|
"type": "promptString"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "replayArg",
|
||||||
|
"type": "promptString",
|
||||||
|
"description": "Enter route or segment to replay."
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"configurations": [
|
"configurations": [
|
||||||
@@ -40,7 +45,41 @@
|
|||||||
"type": "cppdbg",
|
"type": "cppdbg",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceFolder}/${input:cpp_process}",
|
"program": "${workspaceFolder}/${input:cpp_process}",
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Attach LLDB to Replay drive",
|
||||||
|
"type": "lldb",
|
||||||
|
"request": "attach",
|
||||||
|
"pid": "${command:pickMyProcess}",
|
||||||
|
"initCommands": [
|
||||||
|
"script import time; time.sleep(3)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Replay drive",
|
||||||
|
"type": "debugpy",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/opendbc/safety/tests/safety_replay/replay_drive.py",
|
||||||
|
"args": [
|
||||||
|
"${input:replayArg}"
|
||||||
|
],
|
||||||
|
"console": "integratedTerminal",
|
||||||
|
"justMyCode": false,
|
||||||
|
"env": {
|
||||||
|
"PYTHONPATH": "${workspaceFolder}"
|
||||||
|
},
|
||||||
|
"subProcess": true,
|
||||||
|
"stopOnEntry": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"compounds": [
|
||||||
|
{
|
||||||
|
"name": "Replay drive + Safety LLDB",
|
||||||
|
"configurations": [
|
||||||
|
"Replay drive",
|
||||||
|
"Attach LLDB to Replay drive"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM ghcr.io/sunnypilot/sunnypilot-tici-base:latest
|
FROM ghcr.io/sunnypilot/sunnypilot-base:latest
|
||||||
|
|
||||||
ENV PYTHONUNBUFFERED=1
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
|
|||||||
Vendored
+9
-23
@@ -178,7 +178,7 @@ node {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (env.BRANCH_NAME == 'devel-staging') {
|
if (env.BRANCH_NAME == 'devel-staging') {
|
||||||
deviceStage("build release3-staging", "tici-needs-can", [], [
|
deviceStage("build release3-staging", "tizi-needs-can", [], [
|
||||||
step("build release3-staging", "RELEASE_BRANCH=release3-staging $SOURCE_DIR/release/build_release.sh"),
|
step("build release3-staging", "RELEASE_BRANCH=release3-staging $SOURCE_DIR/release/build_release.sh"),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
@@ -186,12 +186,12 @@ node {
|
|||||||
if (env.BRANCH_NAME == '__nightly') {
|
if (env.BRANCH_NAME == '__nightly') {
|
||||||
parallel (
|
parallel (
|
||||||
'nightly': {
|
'nightly': {
|
||||||
deviceStage("build nightly", "tici-needs-can", [], [
|
deviceStage("build nightly", "tizi-needs-can", [], [
|
||||||
step("build nightly", "RELEASE_BRANCH=nightly $SOURCE_DIR/release/build_release.sh"),
|
step("build nightly", "RELEASE_BRANCH=nightly $SOURCE_DIR/release/build_release.sh"),
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
'nightly-dev': {
|
'nightly-dev': {
|
||||||
deviceStage("build nightly-dev", "tici-needs-can", [], [
|
deviceStage("build nightly-dev", "tizi-needs-can", [], [
|
||||||
step("build nightly-dev", "PANDA_DEBUG_BUILD=1 RELEASE_BRANCH=nightly-dev $SOURCE_DIR/release/build_release.sh"),
|
step("build nightly-dev", "PANDA_DEBUG_BUILD=1 RELEASE_BRANCH=nightly-dev $SOURCE_DIR/release/build_release.sh"),
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
@@ -200,39 +200,30 @@ node {
|
|||||||
|
|
||||||
if (!env.BRANCH_NAME.matches(excludeRegex)) {
|
if (!env.BRANCH_NAME.matches(excludeRegex)) {
|
||||||
parallel (
|
parallel (
|
||||||
// tici tests
|
|
||||||
'onroad tests': {
|
'onroad tests': {
|
||||||
deviceStage("onroad", "tici-needs-can", ["UNSAFE=1"], [
|
deviceStage("onroad", "tizi-needs-can", ["UNSAFE=1"], [
|
||||||
step("build openpilot", "cd system/manager && ./build.py"),
|
step("build openpilot", "cd system/manager && ./build.py"),
|
||||||
step("check dirty", "release/check-dirty.sh"),
|
step("check dirty", "release/check-dirty.sh"),
|
||||||
step("onroad tests", "pytest selfdrive/test/test_onroad.py -s", [timeout: 60]),
|
step("onroad tests", "pytest selfdrive/test/test_onroad.py -s", [timeout: 60]),
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
'HW + Unit Tests': {
|
'HW + Unit Tests': {
|
||||||
deviceStage("tici-hardware", "tici-common", ["UNSAFE=1"], [
|
deviceStage("tizi-hardware", "tizi-common", ["UNSAFE=1"], [
|
||||||
step("build", "cd system/manager && ./build.py"),
|
step("build", "cd system/manager && ./build.py"),
|
||||||
step("test pandad", "pytest selfdrive/pandad/tests/test_pandad.py", [diffPaths: ["panda", "selfdrive/pandad/"]]),
|
step("test pandad", "pytest selfdrive/pandad/tests/test_pandad.py", [diffPaths: ["panda", "selfdrive/pandad/"]]),
|
||||||
step("test power draw", "pytest -s system/hardware/tici/tests/test_power_draw.py"),
|
step("test power draw", "pytest -s system/hardware/tici/tests/test_power_draw.py"),
|
||||||
step("test encoder", "LD_LIBRARY_PATH=/usr/local/lib pytest system/loggerd/tests/test_encoder.py", [diffPaths: ["system/loggerd/"]]),
|
step("test encoder", "LD_LIBRARY_PATH=/usr/local/lib pytest system/loggerd/tests/test_encoder.py", [diffPaths: ["system/loggerd/"]]),
|
||||||
step("test pigeond", "pytest system/ubloxd/tests/test_pigeond.py", [diffPaths: ["system/ubloxd/"]]),
|
|
||||||
step("test manager", "pytest system/manager/test/test_manager.py"),
|
step("test manager", "pytest system/manager/test/test_manager.py"),
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
'loopback': {
|
'loopback': {
|
||||||
deviceStage("loopback", "tici-loopback", ["UNSAFE=1"], [
|
deviceStage("loopback", "tizi-loopback", ["UNSAFE=1"], [
|
||||||
step("build openpilot", "cd system/manager && ./build.py"),
|
step("build openpilot", "cd system/manager && ./build.py"),
|
||||||
step("test pandad loopback", "pytest selfdrive/pandad/tests/test_pandad_loopback.py"),
|
step("test pandad loopback", "pytest selfdrive/pandad/tests/test_pandad_loopback.py"),
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
'camerad AR0231': {
|
|
||||||
deviceStage("AR0231", "tici-ar0231", ["UNSAFE=1"], [
|
|
||||||
step("build", "cd system/manager && ./build.py"),
|
|
||||||
step("test camerad", "pytest system/camerad/test/test_camerad.py", [timeout: 60]),
|
|
||||||
step("test exposure", "pytest system/camerad/test/test_exposure.py"),
|
|
||||||
])
|
|
||||||
},
|
|
||||||
'camerad OX03C10': {
|
'camerad OX03C10': {
|
||||||
deviceStage("OX03C10", "tici-ox03c10", ["UNSAFE=1"], [
|
deviceStage("OX03C10", "tizi-ox03c10", ["UNSAFE=1"], [
|
||||||
step("build", "cd system/manager && ./build.py"),
|
step("build", "cd system/manager && ./build.py"),
|
||||||
step("test camerad", "pytest system/camerad/test/test_camerad.py", [timeout: 60]),
|
step("test camerad", "pytest system/camerad/test/test_camerad.py", [timeout: 60]),
|
||||||
step("test exposure", "pytest system/camerad/test/test_exposure.py"),
|
step("test exposure", "pytest system/camerad/test/test_exposure.py"),
|
||||||
@@ -246,17 +237,13 @@ node {
|
|||||||
])
|
])
|
||||||
},
|
},
|
||||||
'sensord': {
|
'sensord': {
|
||||||
deviceStage("LSM + MMC", "tici-lsmc", ["UNSAFE=1"], [
|
deviceStage("LSM + MMC", "tizi-lsmc", ["UNSAFE=1"], [
|
||||||
step("build", "cd system/manager && ./build.py"),
|
|
||||||
step("test sensord", "pytest system/sensord/tests/test_sensord.py"),
|
|
||||||
])
|
|
||||||
deviceStage("BMX + LSM", "tici-bmx-lsm", ["UNSAFE=1"], [
|
|
||||||
step("build", "cd system/manager && ./build.py"),
|
step("build", "cd system/manager && ./build.py"),
|
||||||
step("test sensord", "pytest system/sensord/tests/test_sensord.py"),
|
step("test sensord", "pytest system/sensord/tests/test_sensord.py"),
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
'replay': {
|
'replay': {
|
||||||
deviceStage("model-replay", "tici-replay", ["UNSAFE=1"], [
|
deviceStage("model-replay", "tizi-replay", ["UNSAFE=1"], [
|
||||||
step("build", "cd system/manager && ./build.py", [diffPaths: ["selfdrive/modeld/", "tinygrad_repo", "selfdrive/test/process_replay/model_replay.py"]]),
|
step("build", "cd system/manager && ./build.py", [diffPaths: ["selfdrive/modeld/", "tinygrad_repo", "selfdrive/test/process_replay/model_replay.py"]]),
|
||||||
step("model replay", "selfdrive/test/process_replay/model_replay.py", [diffPaths: ["selfdrive/modeld/", "tinygrad_repo", "selfdrive/test/process_replay/model_replay.py"]]),
|
step("model replay", "selfdrive/test/process_replay/model_replay.py", [diffPaths: ["selfdrive/modeld/", "tinygrad_repo", "selfdrive/test/process_replay/model_replay.py"]]),
|
||||||
])
|
])
|
||||||
@@ -266,7 +253,6 @@ node {
|
|||||||
step("build openpilot", "cd system/manager && ./build.py"),
|
step("build openpilot", "cd system/manager && ./build.py"),
|
||||||
step("test pandad loopback", "SINGLE_PANDA=1 pytest selfdrive/pandad/tests/test_pandad_loopback.py"),
|
step("test pandad loopback", "SINGLE_PANDA=1 pytest selfdrive/pandad/tests/test_pandad_loopback.py"),
|
||||||
step("test pandad spi", "pytest selfdrive/pandad/tests/test_pandad_spi.py"),
|
step("test pandad spi", "pytest selfdrive/pandad/tests/test_pandad_spi.py"),
|
||||||
step("test pandad", "pytest selfdrive/pandad/tests/test_pandad.py", [diffPaths: ["panda", "selfdrive/pandad/"]]),
|
|
||||||
step("test amp", "pytest system/hardware/tici/tests/test_amplifier.py"),
|
step("test amp", "pytest system/hardware/tici/tests/test_amplifier.py"),
|
||||||
// TODO: enable once new AGNOS is available
|
// TODO: enable once new AGNOS is available
|
||||||
// step("test esim", "pytest system/hardware/tici/tests/test_esim.py"),
|
// step("test esim", "pytest system/hardware/tici/tests/test_esim.py"),
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ https://docs.sunnypilot.ai/ is your one stop shop for everything from features t
|
|||||||
Detailed instructions for [how to mount the device in a car](https://comma.ai/setup).
|
Detailed instructions for [how to mount the device in a car](https://comma.ai/setup).
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
Please refer to [Recommended Branches](#-recommended-branches) to find your preferred/supported branch. This guide will assume you want to install the latest `staging-tici` branch.
|
Please refer to [Recommended Branches](#-recommended-branches) to find your preferred/supported branch. This guide will assume you want to install the latest `staging-c3-new` branch.
|
||||||
|
|
||||||
### If you want to use our newest branches (our rewrite)
|
### If you want to use our newest branches (our rewrite)
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
@@ -31,24 +31,25 @@ Please refer to [Recommended Branches](#-recommended-branches) to find your pref
|
|||||||
* sunnypilot not installed or you installed a version before 0.8.17?
|
* sunnypilot not installed or you installed a version before 0.8.17?
|
||||||
1. [Factory reset/uninstall](https://github.com/commaai/openpilot/wiki/FAQ#how-can-i-reset-the-device) the previous software if you have another software/fork installed.
|
1. [Factory reset/uninstall](https://github.com/commaai/openpilot/wiki/FAQ#how-can-i-reset-the-device) the previous software if you have another software/fork installed.
|
||||||
2. After factory reset/uninstall and upon reboot, select `Custom Software` when given the option.
|
2. After factory reset/uninstall and upon reboot, select `Custom Software` when given the option.
|
||||||
3. Input the installation URL per [Recommended Branches](#-recommended-branches). Example: ```https://staging-tici.sunnypilot.ai```.
|
3. Input the installation URL per [Recommended Branches](#-recommended-branches). Example: ```https://staging-c3-new.sunnypilot.ai```.
|
||||||
4. Complete the rest of the installation following the onscreen instructions.
|
4. Complete the rest of the installation following the onscreen instructions.
|
||||||
|
|
||||||
* sunnypilot already installed and you installed a version after 0.8.17?
|
* sunnypilot already installed and you installed a version after 0.8.17?
|
||||||
1. On the comma three, go to `Settings` ▶️ `Software`.
|
1. On the comma three, go to `Settings` ▶️ `Software`.
|
||||||
2. At the `Download` option, press `CHECK`. This will fetch the list of latest branches from sunnypilot.
|
2. At the `Download` option, press `CHECK`. This will fetch the list of latest branches from sunnypilot.
|
||||||
3. At the `Target Branch` option, press `SELECT` to open the Target Branch selector.
|
3. At the `Target Branch` option, press `SELECT` to open the Target Branch selector.
|
||||||
4. Scroll to select the desired branch per Recommended Branches (see below). Example: `staging-tici`
|
4. Scroll to select the desired branch per Recommended Branches (see below). Example: `staging-c3-new`
|
||||||
|
|
||||||
|
|
||||||
| Branch | Installation URL |
|
| Branch | Installation URL |
|
||||||
|:---------------:|:---------------------------------------------:|
|
|:----------------:|:---------------------------------------------:|
|
||||||
| `staging-tici` | `https://staging-tici.sunnypilot.ai` |
|
| `staging-c3-new` | `https://staging-c3-new.sunnypilot.ai` |
|
||||||
| `custom-branch` | `https://install.sunnypilot.ai/{branch_name}` |
|
| `dev-c3-new` | `https://dev-c3-new.sunnypilot.ai` |
|
||||||
| `release-tici` | **Not yet available**. |
|
| `custom-branch` | `https://install.sunnypilot.ai/{branch_name}` |
|
||||||
|
| `release-c3-new` | **Not yet available**. |
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
> You can use sunnypilot/targetbranch as an install URL. Example: 'sunnypilot/staging-tici'.
|
> You can use sunnypilot/targetbranch as an install URL. Example: 'sunnypilot/staging-c3-new'.
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> Do you require further assistance with software installation? Join the [sunnypilot Discord server](https://discord.sunnypilot.com) and message us in the `#installation-help` channel.
|
> Do you require further assistance with software installation? Join the [sunnypilot Discord server](https://discord.sunnypilot.com) and message us in the `#installation-help` channel.
|
||||||
|
|||||||
+8
-2
@@ -1,7 +1,13 @@
|
|||||||
Version 0.10.1 (2025-09-08)
|
Version 0.10.1 (2025-09-08)
|
||||||
========================
|
========================
|
||||||
* Record driving feedback using LKAS button
|
* New driving model
|
||||||
* Honda City 2023 support thanks to drFritz!
|
* World Model: removed global localization inputs
|
||||||
|
* World Model: 2x the number of parameters
|
||||||
|
* World Model: trained on 4x the number of segments
|
||||||
|
* Driving Vision Model: trained on 4x the number of segments
|
||||||
|
* Honda City 2023 support thanks to vanillagorillaa and drFritz!
|
||||||
|
* Honda N-Box 2018 support thanks to miettal!
|
||||||
|
* Honda Odyssey 2021-25 support thanks to csouers and MVL!
|
||||||
|
|
||||||
Version 0.10.0 (2025-08-05)
|
Version 0.10.0 (2025-08-05)
|
||||||
========================
|
========================
|
||||||
|
|||||||
@@ -359,11 +359,6 @@ SConscript([
|
|||||||
'system/ubloxd/SConscript',
|
'system/ubloxd/SConscript',
|
||||||
'system/loggerd/SConscript',
|
'system/loggerd/SConscript',
|
||||||
])
|
])
|
||||||
if arch != "Darwin":
|
|
||||||
SConscript([
|
|
||||||
'system/logcatd/SConscript',
|
|
||||||
'system/proclogd/SConscript',
|
|
||||||
])
|
|
||||||
|
|
||||||
if arch == "larch64":
|
if arch == "larch64":
|
||||||
SConscript(['system/camerad/SConscript'])
|
SConscript(['system/camerad/SConscript'])
|
||||||
|
|||||||
+130
-1
@@ -25,6 +25,26 @@ struct ModularAssistiveDrivingSystem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct IntelligentCruiseButtonManagement {
|
||||||
|
state @0 :IntelligentCruiseButtonManagementState;
|
||||||
|
sendButton @1 :SendButtonState;
|
||||||
|
vTarget @2 :Float32;
|
||||||
|
|
||||||
|
enum IntelligentCruiseButtonManagementState {
|
||||||
|
inactive @0; # No button press or default state
|
||||||
|
preActive @1; # Pre-active state before transitioning to increasing or decreasing
|
||||||
|
increasing @2; # Increasing speed
|
||||||
|
decreasing @3; # Decreasing speed
|
||||||
|
holding @4; # Holding steady speed
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SendButtonState {
|
||||||
|
none @0;
|
||||||
|
increase @1;
|
||||||
|
decrease @2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# Same struct as Log.RadarState.LeadData
|
# Same struct as Log.RadarState.LeadData
|
||||||
struct LeadData {
|
struct LeadData {
|
||||||
dRel @0 :Float32;
|
dRel @0 :Float32;
|
||||||
@@ -48,6 +68,7 @@ struct LeadData {
|
|||||||
|
|
||||||
struct SelfdriveStateSP @0x81c2f05a394cf4af {
|
struct SelfdriveStateSP @0x81c2f05a394cf4af {
|
||||||
mads @0 :ModularAssistiveDrivingSystem;
|
mads @0 :ModularAssistiveDrivingSystem;
|
||||||
|
intelligentCruiseButtonManagement @1 :IntelligentCruiseButtonManagement;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ModelManagerSP @0xaedffd8f31e7b55d {
|
struct ModelManagerSP @0xaedffd8f31e7b55d {
|
||||||
@@ -122,6 +143,13 @@ struct ModelManagerSP @0xaedffd8f31e7b55d {
|
|||||||
|
|
||||||
struct LongitudinalPlanSP @0xf35cc4560bbf6ec2 {
|
struct LongitudinalPlanSP @0xf35cc4560bbf6ec2 {
|
||||||
dec @0 :DynamicExperimentalControl;
|
dec @0 :DynamicExperimentalControl;
|
||||||
|
longitudinalPlanSource @1 :LongitudinalPlanSource;
|
||||||
|
smartCruiseControl @2 :SmartCruiseControl;
|
||||||
|
speedLimit @3 :SpeedLimit;
|
||||||
|
vTarget @4 :Float32;
|
||||||
|
aTarget @5 :Float32;
|
||||||
|
events @6 :List(OnroadEventSP.Event);
|
||||||
|
e2eAlerts @7 :E2eAlerts;
|
||||||
|
|
||||||
struct DynamicExperimentalControl {
|
struct DynamicExperimentalControl {
|
||||||
state @0 :DynamicExperimentalControlState;
|
state @0 :DynamicExperimentalControlState;
|
||||||
@@ -133,6 +161,97 @@ struct LongitudinalPlanSP @0xf35cc4560bbf6ec2 {
|
|||||||
blended @1;
|
blended @1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct SmartCruiseControl {
|
||||||
|
vision @0 :Vision;
|
||||||
|
map @1 :Map;
|
||||||
|
|
||||||
|
struct Vision {
|
||||||
|
state @0 :VisionState;
|
||||||
|
vTarget @1 :Float32;
|
||||||
|
aTarget @2 :Float32;
|
||||||
|
currentLateralAccel @3 :Float32;
|
||||||
|
maxPredictedLateralAccel @4 :Float32;
|
||||||
|
enabled @5 :Bool;
|
||||||
|
active @6 :Bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Map {
|
||||||
|
state @0 :MapState;
|
||||||
|
vTarget @1 :Float32;
|
||||||
|
aTarget @2 :Float32;
|
||||||
|
enabled @3 :Bool;
|
||||||
|
active @4 :Bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum VisionState {
|
||||||
|
disabled @0; # System disabled or inactive.
|
||||||
|
enabled @1; # No predicted substantial turn on vision range.
|
||||||
|
entering @2; # A substantial turn is predicted ahead, adapting speed to turn comfort levels.
|
||||||
|
turning @3; # Actively turning. Managing acceleration to provide a roll on turn feeling.
|
||||||
|
leaving @4; # Road ahead straightens. Start to allow positive acceleration.
|
||||||
|
overriding @5; # System overriding with manual control.
|
||||||
|
}
|
||||||
|
|
||||||
|
enum MapState {
|
||||||
|
disabled @0; # System disabled or inactive.
|
||||||
|
enabled @1; # No predicted substantial turn on map range.
|
||||||
|
turning @2; # Actively turning. Managing acceleration to provide a roll on turn feeling.
|
||||||
|
overriding @3; # System overriding with manual control.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SpeedLimit {
|
||||||
|
resolver @0 :Resolver;
|
||||||
|
assist @1 :Assist;
|
||||||
|
|
||||||
|
struct Resolver {
|
||||||
|
speedLimit @0 :Float32;
|
||||||
|
distToSpeedLimit @1 :Float32;
|
||||||
|
source @2 :Source;
|
||||||
|
speedLimitOffset @3 :Float32;
|
||||||
|
speedLimitLast @4 :Float32;
|
||||||
|
speedLimitFinal @5 :Float32;
|
||||||
|
speedLimitFinalLast @6 :Float32;
|
||||||
|
speedLimitValid @7 :Bool;
|
||||||
|
speedLimitLastValid @8 :Bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Assist {
|
||||||
|
state @0 :AssistState;
|
||||||
|
enabled @1 :Bool;
|
||||||
|
active @2 :Bool;
|
||||||
|
vTarget @3 :Float32;
|
||||||
|
aTarget @4 :Float32;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Source {
|
||||||
|
none @0;
|
||||||
|
car @1;
|
||||||
|
map @2;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum AssistState {
|
||||||
|
disabled @0;
|
||||||
|
inactive @1; # No speed limit set or not enabled by parameter.
|
||||||
|
preActive @2;
|
||||||
|
pending @3; # Awaiting new speed limit.
|
||||||
|
adapting @4; # Reducing speed to match new speed limit.
|
||||||
|
active @5; # Cruising at speed limit.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum LongitudinalPlanSource {
|
||||||
|
cruise @0;
|
||||||
|
sccVision @1;
|
||||||
|
sccMap @2;
|
||||||
|
speedLimitAssist @3;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct E2eAlerts {
|
||||||
|
greenLightAlert @0 :Bool;
|
||||||
|
leadDepartAlert @1 :Bool;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct OnroadEventSP @0xda96579883444c35 {
|
struct OnroadEventSP @0xda96579883444c35 {
|
||||||
@@ -174,12 +293,20 @@ struct OnroadEventSP @0xda96579883444c35 {
|
|||||||
pedalPressedAlertOnly @16;
|
pedalPressedAlertOnly @16;
|
||||||
laneTurnLeft @17;
|
laneTurnLeft @17;
|
||||||
laneTurnRight @18;
|
laneTurnRight @18;
|
||||||
|
speedLimitPreActive @19;
|
||||||
|
speedLimitActive @20;
|
||||||
|
speedLimitChanged @21;
|
||||||
|
speedLimitPending @22;
|
||||||
|
e2eChime @23;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CarParamsSP @0x80ae746ee2596b11 {
|
struct CarParamsSP @0x80ae746ee2596b11 {
|
||||||
flags @0 :UInt32; # flags for car specific quirks in sunnypilot
|
flags @0 :UInt32; # flags for car specific quirks in sunnypilot
|
||||||
safetyParam @1 : Int16; # flags for sunnypilot's custom safety flags
|
safetyParam @1 : Int16; # flags for sunnypilot's custom safety flags
|
||||||
|
pcmCruiseSpeed @3 :Bool;
|
||||||
|
intelligentCruiseButtonManagementAvailable @4 :Bool;
|
||||||
|
enableGasInterceptor @5 :Bool;
|
||||||
|
|
||||||
neuralNetworkLateralControl @2 :NeuralNetworkLateralControl;
|
neuralNetworkLateralControl @2 :NeuralNetworkLateralControl;
|
||||||
|
|
||||||
@@ -199,6 +326,7 @@ struct CarControlSP @0xa5cd762cd951a455 {
|
|||||||
params @1 :List(Param);
|
params @1 :List(Param);
|
||||||
leadOne @2 :LeadData;
|
leadOne @2 :LeadData;
|
||||||
leadTwo @3 :LeadData;
|
leadTwo @3 :LeadData;
|
||||||
|
intelligentCruiseButtonManagement @4 :IntelligentCruiseButtonManagement;
|
||||||
|
|
||||||
struct Param {
|
struct Param {
|
||||||
key @0 :Text;
|
key @0 :Text;
|
||||||
@@ -207,7 +335,7 @@ struct CarControlSP @0xa5cd762cd951a455 {
|
|||||||
|
|
||||||
valueDEPRECATED @1 :Text; # The data type change may cause issues with backwards compatibility.
|
valueDEPRECATED @1 :Text; # The data type change may cause issues with backwards compatibility.
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ParamType {
|
enum ParamType {
|
||||||
string @0;
|
string @0;
|
||||||
bool @1;
|
bool @1;
|
||||||
@@ -262,6 +390,7 @@ struct BackupManagerSP @0xf98d843bfd7004a3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct CarStateSP @0xb86e6369214c01c8 {
|
struct CarStateSP @0xb86e6369214c01c8 {
|
||||||
|
speedLimit @0 :Float32;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LiveMapDataSP @0xf416ec09499d9d19 {
|
struct LiveMapDataSP @0xf416ec09499d9d19 {
|
||||||
|
|||||||
+2
-2
@@ -585,7 +585,6 @@ struct PandaState @0xa7649e2575e4591e {
|
|||||||
heartbeatLost @22 :Bool;
|
heartbeatLost @22 :Bool;
|
||||||
interruptLoad @25 :Float32;
|
interruptLoad @25 :Float32;
|
||||||
fanPower @28 :UInt8;
|
fanPower @28 :UInt8;
|
||||||
fanStallCount @34 :UInt8;
|
|
||||||
|
|
||||||
spiErrorCount @33 :UInt16;
|
spiErrorCount @33 :UInt16;
|
||||||
|
|
||||||
@@ -714,6 +713,7 @@ struct PandaState @0xa7649e2575e4591e {
|
|||||||
usbPowerModeDEPRECATED @12 :PeripheralState.UsbPowerModeDEPRECATED;
|
usbPowerModeDEPRECATED @12 :PeripheralState.UsbPowerModeDEPRECATED;
|
||||||
safetyParamDEPRECATED @20 :Int16;
|
safetyParamDEPRECATED @20 :Int16;
|
||||||
safetyParam2DEPRECATED @26 :UInt32;
|
safetyParam2DEPRECATED @26 :UInt32;
|
||||||
|
fanStallCountDEPRECATED @34 :UInt8;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PeripheralState {
|
struct PeripheralState {
|
||||||
@@ -2684,7 +2684,7 @@ struct Event {
|
|||||||
lateralPlanDEPRECATED @64 :LateralPlan;
|
lateralPlanDEPRECATED @64 :LateralPlan;
|
||||||
navModelDEPRECATED @104 :NavModelData;
|
navModelDEPRECATED @104 :NavModelData;
|
||||||
uiPlanDEPRECATED @106 :UiPlan;
|
uiPlanDEPRECATED @106 :UiPlan;
|
||||||
liveLocationKalmanDEPRECATED @72 :LiveLocationKalman;
|
liveLocationKalman @72 :LiveLocationKalman;
|
||||||
liveTracksDEPRECATED @16 :List(LiveTracksDEPRECATED);
|
liveTracksDEPRECATED @16 :List(LiveTracksDEPRECATED);
|
||||||
onroadEventsDEPRECATED @68: List(Car.OnroadEventDEPRECATED);
|
onroadEventsDEPRECATED @68: List(Car.OnroadEventDEPRECATED);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ MessageContext message_context;
|
|||||||
struct SubMaster::SubMessage {
|
struct SubMaster::SubMessage {
|
||||||
std::string name;
|
std::string name;
|
||||||
SubSocket *socket = nullptr;
|
SubSocket *socket = nullptr;
|
||||||
int freq = 0;
|
float freq = 0.0f;
|
||||||
bool updated = false, alive = false, valid = false, ignore_alive;
|
bool updated = false, alive = false, valid = false, ignore_alive;
|
||||||
uint64_t rcv_time = 0, rcv_frame = 0;
|
uint64_t rcv_time = 0, rcv_frame = 0;
|
||||||
void *allocated_msg_reader = nullptr;
|
void *allocated_msg_reader = nullptr;
|
||||||
|
|||||||
+3
-2
@@ -89,6 +89,7 @@ _services: dict[str, tuple] = {
|
|||||||
"carStateSP": (True, 100., 10),
|
"carStateSP": (True, 100., 10),
|
||||||
"liveMapDataSP": (True, 1., 1),
|
"liveMapDataSP": (True, 1., 1),
|
||||||
"modelDataV2SP": (True, 20.),
|
"modelDataV2SP": (True, 20.),
|
||||||
|
"liveLocationKalman": (True, 20.),
|
||||||
|
|
||||||
# debug
|
# debug
|
||||||
"uiDebug": (True, 0., 1),
|
"uiDebug": (True, 0., 1),
|
||||||
@@ -121,12 +122,12 @@ def build_header():
|
|||||||
h += "#include <map>\n"
|
h += "#include <map>\n"
|
||||||
h += "#include <string>\n"
|
h += "#include <string>\n"
|
||||||
|
|
||||||
h += "struct service { std::string name; bool should_log; int frequency; int decimation; };\n"
|
h += "struct service { std::string name; bool should_log; float frequency; int decimation; };\n"
|
||||||
h += "static std::map<std::string, service> services = {\n"
|
h += "static std::map<std::string, service> services = {\n"
|
||||||
for k, v in SERVICE_LIST.items():
|
for k, v in SERVICE_LIST.items():
|
||||||
should_log = "true" if v.should_log else "false"
|
should_log = "true" if v.should_log else "false"
|
||||||
decimation = -1 if v.decimation is None else v.decimation
|
decimation = -1 if v.decimation is None else v.decimation
|
||||||
h += ' { "%s", {"%s", %s, %d, %d}},\n' % \
|
h += ' { "%s", {"%s", %s, %f, %d}},\n' % \
|
||||||
(k, k, should_log, v.frequency, decimation)
|
(k, k, should_log, v.frequency, decimation)
|
||||||
h += "};\n"
|
h += "};\n"
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
#define DEFAULT_MODEL "Steam Powered (Default)"
|
#define DEFAULT_MODEL "Firehose (Default)"
|
||||||
|
|||||||
+30
-2
@@ -94,7 +94,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"Offroad_NeosUpdate", {CLEAR_ON_MANAGER_START, JSON}},
|
{"Offroad_NeosUpdate", {CLEAR_ON_MANAGER_START, JSON}},
|
||||||
{"Offroad_NoFirmware", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, JSON}},
|
{"Offroad_NoFirmware", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, JSON}},
|
||||||
{"Offroad_Recalibration", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, JSON}},
|
{"Offroad_Recalibration", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, JSON}},
|
||||||
{"Offroad_StorageMissing", {CLEAR_ON_MANAGER_START, JSON}},
|
|
||||||
{"Offroad_TemperatureTooHigh", {CLEAR_ON_MANAGER_START, JSON}},
|
{"Offroad_TemperatureTooHigh", {CLEAR_ON_MANAGER_START, JSON}},
|
||||||
{"Offroad_UnregisteredHardware", {CLEAR_ON_MANAGER_START, JSON}},
|
{"Offroad_UnregisteredHardware", {CLEAR_ON_MANAGER_START, JSON}},
|
||||||
{"Offroad_UpdateFailed", {CLEAR_ON_MANAGER_START, JSON}},
|
{"Offroad_UpdateFailed", {CLEAR_ON_MANAGER_START, JSON}},
|
||||||
@@ -149,17 +148,25 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"DevUIInfo", {PERSISTENT | BACKUP, INT, "0"}},
|
{"DevUIInfo", {PERSISTENT | BACKUP, INT, "0"}},
|
||||||
{"EnableCopyparty", {PERSISTENT | BACKUP, BOOL}},
|
{"EnableCopyparty", {PERSISTENT | BACKUP, BOOL}},
|
||||||
{"EnableGithubRunner", {PERSISTENT | BACKUP, BOOL}},
|
{"EnableGithubRunner", {PERSISTENT | BACKUP, BOOL}},
|
||||||
|
{"GreenLightAlert", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||||
{"GithubRunnerSufficientVoltage", {CLEAR_ON_MANAGER_START , BOOL}},
|
{"GithubRunnerSufficientVoltage", {CLEAR_ON_MANAGER_START , BOOL}},
|
||||||
|
{"IntelligentCruiseButtonManagement", {PERSISTENT | BACKUP , BOOL}},
|
||||||
{"InteractivityTimeout", {PERSISTENT | BACKUP, INT, "0"}},
|
{"InteractivityTimeout", {PERSISTENT | BACKUP, INT, "0"}},
|
||||||
{"IsDevelopmentBranch", {CLEAR_ON_MANAGER_START, BOOL}},
|
{"IsDevelopmentBranch", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||||
|
{"LastGPSPositionLLK", {PERSISTENT, STRING}},
|
||||||
|
{"LeadDepartAlert", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||||
{"MaxTimeOffroad", {PERSISTENT | BACKUP, INT, "1800"}},
|
{"MaxTimeOffroad", {PERSISTENT | BACKUP, INT, "1800"}},
|
||||||
{"ModelRunnerTypeCache", {CLEAR_ON_ONROAD_TRANSITION, INT}},
|
{"ModelRunnerTypeCache", {CLEAR_ON_ONROAD_TRANSITION, INT}},
|
||||||
{"OffroadMode", {CLEAR_ON_MANAGER_START, BOOL}},
|
{"OffroadMode", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||||
{"Offroad_TiciSupport", {CLEAR_ON_MANAGER_START, JSON}},
|
{"Offroad_TiciSupport", {CLEAR_ON_MANAGER_START, JSON}},
|
||||||
|
{"OnroadScreenOffBrightness", {PERSISTENT | BACKUP, INT, "100"}},
|
||||||
|
{"OnroadScreenOffControl", {PERSISTENT | BACKUP, BOOL}},
|
||||||
|
{"OnroadScreenOffTimer", {PERSISTENT | BACKUP, INT, "0"}},
|
||||||
{"QuickBootToggle", {PERSISTENT | BACKUP, BOOL, "0"}},
|
{"QuickBootToggle", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||||
{"QuietMode", {PERSISTENT | BACKUP, BOOL, "0"}},
|
{"QuietMode", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||||
{"RainbowMode", {PERSISTENT | BACKUP, BOOL, "0"}},
|
{"RainbowMode", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||||
{"ShowAdvancedControls", {PERSISTENT | BACKUP, BOOL, "0"}},
|
{"ShowAdvancedControls", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||||
|
{"StandstillTimer", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||||
|
|
||||||
// MADS params
|
// MADS params
|
||||||
{"Mads", {PERSISTENT | BACKUP, BOOL, "1"}},
|
{"Mads", {PERSISTENT | BACKUP, BOOL, "1"}},
|
||||||
@@ -185,7 +192,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"SunnylinkCache_Users", {PERSISTENT, STRING}},
|
{"SunnylinkCache_Users", {PERSISTENT, STRING}},
|
||||||
{"SunnylinkDongleId", {PERSISTENT, STRING}},
|
{"SunnylinkDongleId", {PERSISTENT, STRING}},
|
||||||
{"SunnylinkdPid", {PERSISTENT, INT}},
|
{"SunnylinkdPid", {PERSISTENT, INT}},
|
||||||
{"SunnylinkEnabled", {PERSISTENT, BOOL}},
|
{"SunnylinkEnabled", {PERSISTENT, BOOL, "1"}},
|
||||||
|
|
||||||
// Backup Manager params
|
// Backup Manager params
|
||||||
{"BackupManager_CreateBackup", {PERSISTENT, BOOL}},
|
{"BackupManager_CreateBackup", {PERSISTENT, BOOL}},
|
||||||
@@ -223,4 +230,25 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"OsmStateTitle", {PERSISTENT, STRING}},
|
{"OsmStateTitle", {PERSISTENT, STRING}},
|
||||||
{"OsmWayTest", {PERSISTENT, STRING}},
|
{"OsmWayTest", {PERSISTENT, STRING}},
|
||||||
{"RoadName", {CLEAR_ON_ONROAD_TRANSITION, STRING}},
|
{"RoadName", {CLEAR_ON_ONROAD_TRANSITION, STRING}},
|
||||||
|
{"RoadNameToggle", {PERSISTENT, STRING}},
|
||||||
|
|
||||||
|
// Speed Limit
|
||||||
|
{"SpeedLimitMode", {PERSISTENT | BACKUP, INT, "1"}},
|
||||||
|
{"SpeedLimitOffsetType", {PERSISTENT | BACKUP, INT, "0"}},
|
||||||
|
{"SpeedLimitPolicy", {PERSISTENT | BACKUP, INT, "3"}},
|
||||||
|
{"SpeedLimitValueOffset", {PERSISTENT | BACKUP, INT, "0"}},
|
||||||
|
|
||||||
|
// Smart Cruise Control
|
||||||
|
{"MapTargetVelocities", {CLEAR_ON_ONROAD_TRANSITION, STRING}},
|
||||||
|
{"SmartCruiseControlMap", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||||
|
{"SmartCruiseControlVision", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||||
|
|
||||||
|
// Torque lateral control custom params
|
||||||
|
{"CustomTorqueParams", {PERSISTENT | BACKUP , BOOL}},
|
||||||
|
{"EnforceTorqueControl", {PERSISTENT | BACKUP, BOOL}},
|
||||||
|
{"LiveTorqueParamsToggle", {PERSISTENT | BACKUP , BOOL}},
|
||||||
|
{"LiveTorqueParamsRelaxedToggle", {PERSISTENT | BACKUP , BOOL}},
|
||||||
|
{"TorqueParamsOverrideEnabled", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||||
|
{"TorqueParamsOverrideFriction", {PERSISTENT | BACKUP, FLOAT, "0.1"}},
|
||||||
|
{"TorqueParamsOverrideLatAccelFactor", {PERSISTENT | BACKUP, FLOAT, "2.5"}},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ const double MS_TO_KPH = 3.6;
|
|||||||
const double MS_TO_MPH = MS_TO_KPH * KM_TO_MILE;
|
const double MS_TO_MPH = MS_TO_KPH * KM_TO_MILE;
|
||||||
const double METER_TO_MILE = KM_TO_MILE / 1000.0;
|
const double METER_TO_MILE = KM_TO_MILE / 1000.0;
|
||||||
const double METER_TO_FOOT = 3.28084;
|
const double METER_TO_FOOT = 3.28084;
|
||||||
|
const double METER_TO_KM = 1. / 1000.0;
|
||||||
|
|
||||||
#define ALIGNED_SIZE(x, align) (((x) + (align)-1) & ~((align)-1))
|
#define ALIGNED_SIZE(x, align) (((x) + (align)-1) & ~((align)-1))
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ All of these are examples of good PRs:
|
|||||||
### First contribution
|
### First contribution
|
||||||
|
|
||||||
[Projects / openpilot bounties](https://github.com/orgs/commaai/projects/26/views/1?pane=info) is the best place to get started and goes in-depth on what's expected when working on a bounty.
|
[Projects / openpilot bounties](https://github.com/orgs/commaai/projects/26/views/1?pane=info) is the best place to get started and goes in-depth on what's expected when working on a bounty.
|
||||||
There's lot of bounties that don't require a comma 3/3X or a car.
|
There's lot of bounties that don't require a comma 3X or a car.
|
||||||
|
|
||||||
## Pull Requests
|
## Pull Requests
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# Debugging Panda Safety with Replay Drive + LLDB
|
||||||
|
|
||||||
|
## 1. Start the debugger in VS Code
|
||||||
|
|
||||||
|
* Select **Replay drive + Safety LLDB**.
|
||||||
|
* Enter the route or segment when prompted.
|
||||||
|
[<img src="https://github.com/user-attachments/assets/b0cc320a-083e-46a7-a9f8-ca775bbe5604">](https://github.com/user-attachments/assets/b0cc320a-083e-46a7-a9f8-ca775bbe5604)
|
||||||
|
|
||||||
|
## 2. Attach LLDB
|
||||||
|
|
||||||
|
* When prompted, pick the running **`replay_drive` process**.
|
||||||
|
* ⚠️ Attach quickly, or `replay_drive` will start consuming messages.
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> Add a Python breakpoint at the start of `replay_drive.py` to pause execution and give yourself time to attach LLDB.
|
||||||
|
|
||||||
|
## 3. Set breakpoints in VS Code
|
||||||
|
Breakpoints can be set directly in `modes/xxx.h` (or any C file).
|
||||||
|
No extra LLDB commands are required — just place breakpoints in the editor.
|
||||||
|
|
||||||
|
## 4. Resume execution
|
||||||
|
Once attached, you can step through both Python (on the replay) and C safety code as CAN logs are replayed.
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> * Use short routes for quicker iteration.
|
||||||
|
> * Pause `replay_drive` early to avoid wasting log messages.
|
||||||
|
|
||||||
|
## Video
|
||||||
|
|
||||||
|
View a demo of this workflow on the PR that added it: https://github.com/commaai/openpilot/pull/36055#issue-3352911578
|
||||||
+14
-4
@@ -16,7 +16,7 @@ industry standards of safety for Level 2 Driver Assistance Systems. In particula
|
|||||||
ISO26262 guidelines, including those from [pertinent documents](https://www.nhtsa.gov/sites/nhtsa.dot.gov/files/documents/13498a_812_573_alcsystemreport.pdf)
|
ISO26262 guidelines, including those from [pertinent documents](https://www.nhtsa.gov/sites/nhtsa.dot.gov/files/documents/13498a_812_573_alcsystemreport.pdf)
|
||||||
released by NHTSA. In addition, we impose strict coding guidelines (like [MISRA C : 2012](https://www.misra.org.uk/what-is-misra/))
|
released by NHTSA. In addition, we impose strict coding guidelines (like [MISRA C : 2012](https://www.misra.org.uk/what-is-misra/))
|
||||||
on parts of openpilot that are safety relevant. We also perform software-in-the-loop,
|
on parts of openpilot that are safety relevant. We also perform software-in-the-loop,
|
||||||
hardware-in-the-loop and in-vehicle tests before each software release.
|
hardware-in-the-loop, and in-vehicle tests before each software release.
|
||||||
|
|
||||||
Following Hazard and Risk Analysis and FMEA, at a very high level, we have designed openpilot
|
Following Hazard and Risk Analysis and FMEA, at a very high level, we have designed openpilot
|
||||||
ensuring two main safety requirements.
|
ensuring two main safety requirements.
|
||||||
@@ -29,8 +29,18 @@ ensuring two main safety requirements.
|
|||||||
|
|
||||||
For additional safety implementation details, refer to [panda safety model](https://github.com/commaai/panda#safety-model). For vehicle specific implementation of the safety concept, refer to [opendbc/safety/safety](https://github.com/commaai/opendbc/tree/master/opendbc/safety/safety).
|
For additional safety implementation details, refer to [panda safety model](https://github.com/commaai/panda#safety-model). For vehicle specific implementation of the safety concept, refer to [opendbc/safety/safety](https://github.com/commaai/opendbc/tree/master/opendbc/safety/safety).
|
||||||
|
|
||||||
**Extra note**: comma.ai strongly discourages the use of openpilot forks with safety code either missing or
|
[^1]: For these actuator limits we observe ISO11270 and ISO15622. Lateral limits described there translate to 0.9 seconds of maximum actuation to achieve a 1m lateral deviation.
|
||||||
not fully meeting the above requirements.
|
|
||||||
|
|
||||||
[^1]: For these actuator limits we observe ISO11270 and ISO15622. Lateral limits described there translate to 0.9 seconds of maximum actuation to achieve a 1m lateral deviation.
|
---
|
||||||
|
|
||||||
|
### Forks of openpilot
|
||||||
|
|
||||||
|
* Do not disable or nerf [driver monitoring](https://github.com/commaai/openpilot/tree/master/selfdrive/monitoring)
|
||||||
|
* Do not disable or nerf [excessive actuation checks](https://github.com/commaai/openpilot/tree/master/selfdrive/selfdrived/helpers.py)
|
||||||
|
* If your fork modifies any of the code in `opendbc/safety/`:
|
||||||
|
* your fork cannot use the openpilot trademark
|
||||||
|
* your fork must preserve the full [safety test suite](https://github.com/commaai/opendbc/tree/master/opendbc/safety/tests) and all tests must pass, including any new coverage required by the fork's changes
|
||||||
|
|
||||||
|
Failure to comply with these standards will get you and your users banned from comma.ai servers.
|
||||||
|
|
||||||
|
**comma.ai strongly discourages the use of openpilot forks with safety code either missing or not fully meeting the above requirements.**
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
# connect to a comma 3/3X
|
# connect to a comma 3X
|
||||||
|
|
||||||
A comma 3/3X is a normal [Linux](https://github.com/commaai/agnos-builder) computer that exposes [SSH](https://wiki.archlinux.org/title/Secure_Shell) and a [serial console](https://wiki.archlinux.org/title/Working_with_the_serial_console).
|
A comma 3X is a normal [Linux](https://github.com/commaai/agnos-builder) computer that exposes [SSH](https://wiki.archlinux.org/title/Secure_Shell) and a [serial console](https://wiki.archlinux.org/title/Working_with_the_serial_console).
|
||||||
|
|
||||||
## Serial Console
|
## Serial Console
|
||||||
|
|
||||||
On both the comma three and 3X, the serial console is accessible from the main OBD-C port.
|
On both the comma three and 3X, the serial console is accessible from the main OBD-C port.
|
||||||
Connect the comma 3/3X to your computer with a normal USB C cable, or use a [comma serial](https://comma.ai/shop/comma-serial) for steady 12V power.
|
Connect the comma 3X to your computer with a normal USB C cable, or use a [comma serial](https://comma.ai/shop/comma-serial) for steady 12V power.
|
||||||
|
|
||||||
On the comma three, the serial console is exposed through a UART-to-USB chip, and `tools/scripts/serial.sh` can be used to connect.
|
On the comma three, the serial console is exposed through a UART-to-USB chip, and `tools/scripts/serial.sh` can be used to connect.
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ In order to use ADB on your device, you'll need to perform the following steps u
|
|||||||
* Here's an example command for connecting to your device using its tethered connection: `adb connect 192.168.43.1:5555`
|
* Here's an example command for connecting to your device using its tethered connection: `adb connect 192.168.43.1:5555`
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> The default port for ADB is 5555 on the comma 3/3X.
|
> The default port for ADB is 5555 on the comma 3X.
|
||||||
|
|
||||||
For more info on ADB, see the [Android Debug Bridge (ADB) documentation](https://developer.android.com/tools/adb).
|
For more info on ADB, see the [Android Debug Bridge (ADB) documentation](https://developer.android.com/tools/adb).
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ Replaying is a critical tool for openpilot development and debugging.
|
|||||||
Just run `tools/replay/replay --demo`.
|
Just run `tools/replay/replay --demo`.
|
||||||
|
|
||||||
## Replaying CAN data
|
## Replaying CAN data
|
||||||
*Hardware required: jungle and comma 3/3X*
|
*Hardware required: jungle and comma 3X*
|
||||||
|
|
||||||
1. Connect your PC to a jungle.
|
1. Connect your PC to a jungle.
|
||||||
2.
|
2.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
In 30 minutes, we'll get an openpilot development environment set up on your computer and make some changes to openpilot's UI.
|
In 30 minutes, we'll get an openpilot development environment set up on your computer and make some changes to openpilot's UI.
|
||||||
|
|
||||||
And if you have a comma 3/3X, we'll deploy the change to your device for testing.
|
And if you have a comma 3X, we'll deploy the change to your device for testing.
|
||||||
|
|
||||||
## 1. Set up your development environment
|
## 1. Set up your development environment
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@ export OPENBLAS_NUM_THREADS=1
|
|||||||
export VECLIB_MAXIMUM_THREADS=1
|
export VECLIB_MAXIMUM_THREADS=1
|
||||||
|
|
||||||
if [ -z "$AGNOS_VERSION" ]; then
|
if [ -z "$AGNOS_VERSION" ]; then
|
||||||
export AGNOS_VERSION="12.8"
|
export AGNOS_VERSION="13.1"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
export STAGING_ROOT="/data/safe_staging"
|
export STAGING_ROOT="/data/safe_staging"
|
||||||
|
|||||||
+1
-1
@@ -21,7 +21,7 @@ nav:
|
|||||||
- What is openpilot?: getting-started/what-is-openpilot.md
|
- What is openpilot?: getting-started/what-is-openpilot.md
|
||||||
- How-to:
|
- How-to:
|
||||||
- Turn the speed blue: how-to/turn-the-speed-blue.md
|
- Turn the speed blue: how-to/turn-the-speed-blue.md
|
||||||
- Connect to a comma 3/3X: how-to/connect-to-comma.md
|
- Connect to a comma 3X: how-to/connect-to-comma.md
|
||||||
# - Make your first pull request: how-to/make-first-pr.md
|
# - Make your first pull request: how-to/make-first-pr.md
|
||||||
#- Replay a drive: how-to/replay-a-drive.md
|
#- Replay a drive: how-to/replay-a-drive.md
|
||||||
- Concepts:
|
- Concepts:
|
||||||
|
|||||||
+1
-1
Submodule opendbc_repo updated: 1a1fd1af7f...29fe003b2f
+1
-1
Submodule panda updated: 7eab6fd61b...69ab12ee2a
+8
-3
@@ -36,6 +36,9 @@ dependencies = [
|
|||||||
"pyopenssl < 24.3.0",
|
"pyopenssl < 24.3.0",
|
||||||
"pyaudio",
|
"pyaudio",
|
||||||
|
|
||||||
|
# ubloxd (TODO: just use struct)
|
||||||
|
"kaitaistruct",
|
||||||
|
|
||||||
# panda
|
# panda
|
||||||
"libusb1",
|
"libusb1",
|
||||||
"spidev; platform_system == 'Linux'",
|
"spidev; platform_system == 'Linux'",
|
||||||
@@ -101,8 +104,9 @@ dev = [
|
|||||||
"av",
|
"av",
|
||||||
"azure-identity",
|
"azure-identity",
|
||||||
"azure-storage-blob",
|
"azure-storage-blob",
|
||||||
"dbus-next",
|
"dbus-next", # TODO: remove once we moved everything to jeepney
|
||||||
"dictdiffer",
|
"dictdiffer",
|
||||||
|
"jeepney",
|
||||||
"matplotlib",
|
"matplotlib",
|
||||||
"opencv-python-headless",
|
"opencv-python-headless",
|
||||||
"parameterized >=0.8, <0.9",
|
"parameterized >=0.8, <0.9",
|
||||||
@@ -120,6 +124,7 @@ dev = [
|
|||||||
|
|
||||||
tools = [
|
tools = [
|
||||||
"metadrive-simulator @ https://github.com/commaai/metadrive/releases/download/MetaDrive-minimal-0.4.2.4/metadrive_simulator-0.4.2.4-py3-none-any.whl ; (platform_machine != 'aarch64')",
|
"metadrive-simulator @ https://github.com/commaai/metadrive/releases/download/MetaDrive-minimal-0.4.2.4/metadrive_simulator-0.4.2.4-py3-none-any.whl ; (platform_machine != 'aarch64')",
|
||||||
|
"dearpygui>=2.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
@@ -157,7 +162,6 @@ testpaths = [
|
|||||||
"system/camerad",
|
"system/camerad",
|
||||||
"system/hardware",
|
"system/hardware",
|
||||||
"system/loggerd",
|
"system/loggerd",
|
||||||
"system/proclogd",
|
|
||||||
"system/tests",
|
"system/tests",
|
||||||
"system/ubloxd",
|
"system/ubloxd",
|
||||||
"system/webrtc",
|
"system/webrtc",
|
||||||
@@ -173,7 +177,7 @@ quiet-level = 3
|
|||||||
# if you've got a short variable name that's getting flagged, add it here
|
# if you've got a short variable name that's getting flagged, add it here
|
||||||
ignore-words-list = "bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints,whit,indexIn,ws,uint,grey,deque,stdio,amin,BA,LITE,atEnd,UIs,errorString,arange,FocusIn,od,tim,relA,hist,copyable,jupyter,thead,TGE,abl,lite"
|
ignore-words-list = "bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints,whit,indexIn,ws,uint,grey,deque,stdio,amin,BA,LITE,atEnd,UIs,errorString,arange,FocusIn,od,tim,relA,hist,copyable,jupyter,thead,TGE,abl,lite"
|
||||||
builtin = "clear,rare,informal,code,names,en-GB_to_en-US"
|
builtin = "clear,rare,informal,code,names,en-GB_to_en-US"
|
||||||
skip = "./third_party/*, ./tinygrad/*, ./tinygrad_repo/*, ./msgq/*, ./panda/*, ./opendbc/*, ./opendbc_repo/*, ./rednose/*, ./rednose_repo/*, ./teleoprtc/*, ./teleoprtc_repo/*, *.ts, uv.lock, *.onnx, ./cereal/gen/*, */c_generated_code/*, docs/assets/*"
|
skip = "./third_party/*, ./tinygrad/*, ./tinygrad_repo/*, ./msgq/*, ./panda/*, ./opendbc/*, ./opendbc_repo/*, ./rednose/*, ./rednose_repo/*, ./teleoprtc/*, ./teleoprtc_repo/*, *.ts, uv.lock, *.onnx, ./cereal/gen/*, */c_generated_code/*, docs/assets/*, tools/plotjuggler/layouts/*"
|
||||||
|
|
||||||
[tool.mypy]
|
[tool.mypy]
|
||||||
python_version = "3.11"
|
python_version = "3.11"
|
||||||
@@ -247,6 +251,7 @@ exclude = [
|
|||||||
"teleoprtc_repo",
|
"teleoprtc_repo",
|
||||||
"third_party",
|
"third_party",
|
||||||
"*.ipynb",
|
"*.ipynb",
|
||||||
|
"generated",
|
||||||
]
|
]
|
||||||
lint.flake8-implicit-str-concat.allow-multiline = false
|
lint.flake8-implicit-str-concat.allow-multiline = false
|
||||||
|
|
||||||
|
|||||||
@@ -31,25 +31,13 @@ while read hash submodule ref; do
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
# Check against master-tici for specific submodules, master for others
|
git -C $submodule fetch --depth 100 origin master
|
||||||
if [ "$submodule" = "opendbc_repo" ] || [ "$submodule" = "panda" ]; then
|
git -C $submodule branch -r --contains $hash | grep "origin/master"
|
||||||
git -C $submodule fetch --depth 100 origin master-tici
|
if [ "$?" -eq 0 ]; then
|
||||||
remote_hash=$(git -C $submodule rev-parse FETCH_HEAD)
|
echo "$submodule ok"
|
||||||
if git -C $submodule merge-base --is-ancestor $hash $remote_hash; then
|
|
||||||
echo "$submodule ok"
|
|
||||||
else
|
|
||||||
echo "$submodule: $hash is not on master-tici"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
git -C $submodule fetch --depth 100 origin master
|
echo "$submodule: $hash is not on master"
|
||||||
git -C $submodule branch -r --contains $hash | grep "origin/master"
|
exit 1
|
||||||
if [ "$?" -eq 0 ]; then
|
|
||||||
echo "$submodule ok"
|
|
||||||
else
|
|
||||||
echo "$submodule: $hash is not on master"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done <<< $(git submodule status --recursive)
|
done <<< $(git submodule status --recursive)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
if [ "$1" = "base" ]; then
|
if [ "$1" = "base" ]; then
|
||||||
export DOCKER_IMAGE=sunnypilot-tici-base
|
export DOCKER_IMAGE=sunnypilot-base
|
||||||
export DOCKER_FILE=Dockerfile.sunnypilot_base
|
export DOCKER_FILE=Dockerfile.sunnypilot_base
|
||||||
elif [ "$1" = "prebuilt" ]; then
|
elif [ "$1" = "prebuilt" ]; then
|
||||||
export DOCKER_IMAGE=sunnypilot-tici-prebuilt
|
export DOCKER_IMAGE=sunnypilot-prebuilt
|
||||||
export DOCKER_FILE=Dockerfile.sunnypilot
|
export DOCKER_FILE=Dockerfile.sunnypilot
|
||||||
else
|
else
|
||||||
echo "Invalid docker build image: '$1'"
|
echo "Invalid docker build image: '$1'"
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ def setup_argument_parser():
|
|||||||
parser.add_argument('--pr-data', type=str, help='PR data in JSON format')
|
parser.add_argument('--pr-data', type=str, help='PR data in JSON format')
|
||||||
parser.add_argument('--source-branch', type=str, default='master',
|
parser.add_argument('--source-branch', type=str, default='master',
|
||||||
help='Source branch for merging')
|
help='Source branch for merging')
|
||||||
parser.add_argument('--target-branch', type=str, default='master-dev-c3-new-test',
|
parser.add_argument('--target-branch', type=str, default='master-dev-test',
|
||||||
help='Target branch for merging')
|
help='Target branch for merging')
|
||||||
parser.add_argument('--squash-script-path', type=str, required=True,
|
parser.add_argument('--squash-script-path', type=str, required=True,
|
||||||
help='Path to the squash_and_merge.py script')
|
help='Path to the squash_and_merge.py script')
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ class Car:
|
|||||||
|
|
||||||
def __init__(self, CI=None, RI=None) -> None:
|
def __init__(self, CI=None, RI=None) -> None:
|
||||||
self.can_sock = messaging.sub_sock('can', timeout=20)
|
self.can_sock = messaging.sub_sock('can', timeout=20)
|
||||||
self.sm = messaging.SubMaster(['pandaStates', 'carControl', 'onroadEvents'] + ['carControlSP'])
|
self.sm = messaging.SubMaster(['pandaStates', 'carControl', 'onroadEvents'] + ['carControlSP', 'longitudinalPlanSP'])
|
||||||
self.pm = messaging.PubMaster(['sendcan', 'carState', 'carParams', 'carOutput', 'liveTracks'] + ['carParamsSP', 'carStateSP'])
|
self.pm = messaging.PubMaster(['sendcan', 'carState', 'carParams', 'carOutput', 'liveTracks'] + ['carParamsSP', 'carStateSP'])
|
||||||
|
|
||||||
self.can_rcv_cum_timeout_counter = 0
|
self.can_rcv_cum_timeout_counter = 0
|
||||||
@@ -124,7 +124,7 @@ class Car:
|
|||||||
|
|
||||||
self.CP.alternativeExperience = 0
|
self.CP.alternativeExperience = 0
|
||||||
# mads
|
# mads
|
||||||
set_alternative_experience(self.CP, self.params)
|
set_alternative_experience(self.CP, self.CP_SP, self.params)
|
||||||
set_car_specific_params(self.CP, self.CP_SP, self.params)
|
set_car_specific_params(self.CP, self.CP_SP, self.params)
|
||||||
|
|
||||||
# Dynamic Experimental Control
|
# Dynamic Experimental Control
|
||||||
@@ -179,7 +179,7 @@ class Car:
|
|||||||
self.params.put_nonblocking("CarParamsSPPersistent", cp_sp_bytes)
|
self.params.put_nonblocking("CarParamsSPPersistent", cp_sp_bytes)
|
||||||
|
|
||||||
self.mock_carstate = MockCarState()
|
self.mock_carstate = MockCarState()
|
||||||
self.v_cruise_helper = VCruiseHelper(self.CP)
|
self.v_cruise_helper = VCruiseHelper(self.CP, self.CP_SP)
|
||||||
|
|
||||||
self.is_metric = self.params.get_bool("IsMetric")
|
self.is_metric = self.params.get_bool("IsMetric")
|
||||||
self.experimental_mode = self.params.get_bool("ExperimentalMode")
|
self.experimental_mode = self.params.get_bool("ExperimentalMode")
|
||||||
@@ -216,6 +216,7 @@ class Car:
|
|||||||
if can_rcv_valid and REPLAY:
|
if can_rcv_valid and REPLAY:
|
||||||
self.can_log_mono_time = messaging.log_from_bytes(can_strs[0]).logMonoTime
|
self.can_log_mono_time = messaging.log_from_bytes(can_strs[0]).logMonoTime
|
||||||
|
|
||||||
|
self.v_cruise_helper.update_speed_limit_assist(self.is_metric, self.sm['longitudinalPlanSP'])
|
||||||
self.v_cruise_helper.update_v_cruise(CS, self.sm['carControl'].enabled, self.is_metric)
|
self.v_cruise_helper.update_v_cruise(CS, self.sm['carControl'].enabled, self.is_metric)
|
||||||
if self.sm['carControl'].enabled and not self.CC_prev.enabled:
|
if self.sm['carControl'].enabled and not self.CC_prev.enabled:
|
||||||
# Use CarState w/ buttons from the step selfdrived enables on
|
# Use CarState w/ buttons from the step selfdrived enables on
|
||||||
|
|||||||
+15
-5
@@ -30,8 +30,8 @@ CRUISE_INTERVAL_SIGN = {
|
|||||||
|
|
||||||
|
|
||||||
class VCruiseHelper(VCruiseHelperSP):
|
class VCruiseHelper(VCruiseHelperSP):
|
||||||
def __init__(self, CP):
|
def __init__(self, CP, CP_SP):
|
||||||
VCruiseHelperSP.__init__(self)
|
VCruiseHelperSP.__init__(self, CP, CP_SP)
|
||||||
self.CP = CP
|
self.CP = CP
|
||||||
self.v_cruise_kph = V_CRUISE_UNSET
|
self.v_cruise_kph = V_CRUISE_UNSET
|
||||||
self.v_cruise_cluster_kph = V_CRUISE_UNSET
|
self.v_cruise_cluster_kph = V_CRUISE_UNSET
|
||||||
@@ -46,10 +46,14 @@ class VCruiseHelper(VCruiseHelperSP):
|
|||||||
def update_v_cruise(self, CS, enabled, is_metric):
|
def update_v_cruise(self, CS, enabled, is_metric):
|
||||||
self.v_cruise_kph_last = self.v_cruise_kph
|
self.v_cruise_kph_last = self.v_cruise_kph
|
||||||
|
|
||||||
|
self.get_minimum_set_speed(is_metric)
|
||||||
|
|
||||||
if CS.cruiseState.available:
|
if CS.cruiseState.available:
|
||||||
if not self.CP.pcmCruise:
|
_enabled = self.update_enabled_state(CS, enabled)
|
||||||
|
if not self.CP.pcmCruise or (not self.CP_SP.pcmCruiseSpeed and _enabled):
|
||||||
# if stock cruise is completely disabled, then we can use our own set speed logic
|
# if stock cruise is completely disabled, then we can use our own set speed logic
|
||||||
self._update_v_cruise_non_pcm(CS, enabled, is_metric)
|
self._update_v_cruise_non_pcm(CS, _enabled, is_metric)
|
||||||
|
self.update_speed_limit_assist_v_cruise_non_pcm()
|
||||||
self.v_cruise_cluster_kph = self.v_cruise_kph
|
self.v_cruise_cluster_kph = self.v_cruise_kph
|
||||||
self.update_button_timers(CS, enabled)
|
self.update_button_timers(CS, enabled)
|
||||||
else:
|
else:
|
||||||
@@ -101,6 +105,12 @@ class VCruiseHelper(VCruiseHelperSP):
|
|||||||
if not self.button_change_states[button_type]["enabled"]:
|
if not self.button_change_states[button_type]["enabled"]:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Speed Limit Assist for Non PCM long cars.
|
||||||
|
# True: Disallow set speed changes when user confirmed the target set speed during preActive state
|
||||||
|
# False: Allow set speed changes as SLA is not requesting user confirmation
|
||||||
|
if self.update_speed_limit_assist_pre_active_confirmed(button_type):
|
||||||
|
return
|
||||||
|
|
||||||
long_press, v_cruise_delta = VCruiseHelperSP.update_v_cruise_delta(self, long_press, v_cruise_delta)
|
long_press, v_cruise_delta = VCruiseHelperSP.update_v_cruise_delta(self, long_press, v_cruise_delta)
|
||||||
if long_press and self.v_cruise_kph % v_cruise_delta != 0: # partial interval
|
if long_press and self.v_cruise_kph % v_cruise_delta != 0: # partial interval
|
||||||
self.v_cruise_kph = CRUISE_NEAREST_FUNC[button_type](self.v_cruise_kph / v_cruise_delta) * v_cruise_delta
|
self.v_cruise_kph = CRUISE_NEAREST_FUNC[button_type](self.v_cruise_kph / v_cruise_delta) * v_cruise_delta
|
||||||
@@ -111,7 +121,7 @@ class VCruiseHelper(VCruiseHelperSP):
|
|||||||
if CS.gasPressed and button_type in (ButtonType.decelCruise, ButtonType.setCruise):
|
if CS.gasPressed and button_type in (ButtonType.decelCruise, ButtonType.setCruise):
|
||||||
self.v_cruise_kph = max(self.v_cruise_kph, CS.vEgo * CV.MS_TO_KPH)
|
self.v_cruise_kph = max(self.v_cruise_kph, CS.vEgo * CV.MS_TO_KPH)
|
||||||
|
|
||||||
self.v_cruise_kph = np.clip(round(self.v_cruise_kph, 1), V_CRUISE_MIN, V_CRUISE_MAX)
|
self.v_cruise_kph = np.clip(round(self.v_cruise_kph, 1), self.v_cruise_min, V_CRUISE_MAX)
|
||||||
|
|
||||||
def update_button_timers(self, CS, enabled):
|
def update_button_timers(self, CS, enabled):
|
||||||
# increment timer for buttons still pressed
|
# increment timer for buttons still pressed
|
||||||
|
|||||||
@@ -60,5 +60,8 @@ def convert_carControlSP(struct: capnp.lib.capnp._DynamicStructReader) -> struct
|
|||||||
struct_dataclass.params = [structs.CarControlSP.Param(**remove_deprecated(p)) for p in struct_dict.get('params', [])]
|
struct_dataclass.params = [structs.CarControlSP.Param(**remove_deprecated(p)) for p in struct_dict.get('params', [])]
|
||||||
struct_dataclass.leadOne = structs.LeadData(**remove_deprecated(struct_dict.get('leadOne', {})))
|
struct_dataclass.leadOne = structs.LeadData(**remove_deprecated(struct_dict.get('leadOne', {})))
|
||||||
struct_dataclass.leadTwo = structs.LeadData(**remove_deprecated(struct_dict.get('leadTwo', {})))
|
struct_dataclass.leadTwo = structs.LeadData(**remove_deprecated(struct_dict.get('leadTwo', {})))
|
||||||
|
struct_dataclass.intelligentCruiseButtonManagement = structs.IntelligentCruiseButtonManagement(
|
||||||
|
**remove_deprecated(struct_dict.get('intelligentCruiseButtonManagement', {}))
|
||||||
|
)
|
||||||
|
|
||||||
return struct_dataclass
|
return struct_dataclass
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
import os
|
import os
|
||||||
import math
|
|
||||||
import hypothesis.strategies as st
|
import hypothesis.strategies as st
|
||||||
from hypothesis import Phase, given, settings
|
from hypothesis import Phase, given, settings
|
||||||
from parameterized import parameterized
|
from parameterized import parameterized
|
||||||
|
|
||||||
from cereal import car, custom
|
from cereal import car, custom
|
||||||
from opendbc.car import DT_CTRL
|
from opendbc.car import DT_CTRL
|
||||||
from opendbc.car.car_helpers import interfaces
|
|
||||||
from opendbc.car.structs import CarParams
|
from opendbc.car.structs import CarParams
|
||||||
from opendbc.car.tests.test_car_interfaces import get_fuzzy_car_interface_args
|
from opendbc.car.tests.test_car_interfaces import get_fuzzy_car_interface
|
||||||
from opendbc.car.fw_versions import FW_VERSIONS, FW_QUERY_CONFIGS
|
|
||||||
from opendbc.car.mock.values import CAR as MOCK
|
from opendbc.car.mock.values import CAR as MOCK
|
||||||
from opendbc.car.values import PLATFORMS
|
from opendbc.car.values import PLATFORMS
|
||||||
from openpilot.selfdrive.car.helpers import convert_carControlSP
|
from openpilot.selfdrive.car.helpers import convert_carControlSP
|
||||||
@@ -21,11 +18,6 @@ from openpilot.selfdrive.test.fuzzy_generation import FuzzyGenerator
|
|||||||
|
|
||||||
from openpilot.sunnypilot.selfdrive.car import interfaces as sunnypilot_interfaces
|
from openpilot.sunnypilot.selfdrive.car import interfaces as sunnypilot_interfaces
|
||||||
|
|
||||||
ALL_ECUS = {ecu for ecus in FW_VERSIONS.values() for ecu in ecus.keys()}
|
|
||||||
ALL_ECUS |= {ecu for config in FW_QUERY_CONFIGS.values() for ecu in config.extra_ecus}
|
|
||||||
|
|
||||||
ALL_REQUESTS = {tuple(r.request) for config in FW_QUERY_CONFIGS.values() for r in config.requests}
|
|
||||||
|
|
||||||
MAX_EXAMPLES = int(os.environ.get('MAX_EXAMPLES', '60'))
|
MAX_EXAMPLES = int(os.environ.get('MAX_EXAMPLES', '60'))
|
||||||
|
|
||||||
|
|
||||||
@@ -37,43 +29,10 @@ class TestCarInterfaces:
|
|||||||
phases=(Phase.reuse, Phase.generate, Phase.shrink))
|
phases=(Phase.reuse, Phase.generate, Phase.shrink))
|
||||||
@given(data=st.data())
|
@given(data=st.data())
|
||||||
def test_car_interfaces(self, car_name, data):
|
def test_car_interfaces(self, car_name, data):
|
||||||
CarInterface = interfaces[car_name]
|
car_interface = get_fuzzy_car_interface(car_name, data.draw)
|
||||||
|
car_params = car_interface.CP.as_reader()
|
||||||
args = get_fuzzy_car_interface_args(data.draw)
|
car_params_sp = car_interface.CP_SP
|
||||||
|
|
||||||
car_params = CarInterface.get_params(car_name, args['fingerprints'], args['car_fw'],
|
|
||||||
alpha_long=args['alpha_long'], is_release=False, docs=False)
|
|
||||||
car_params_sp = CarInterface.get_params_sp(car_params, car_name, args['fingerprints'], args['car_fw'],
|
|
||||||
alpha_long=args['alpha_long'], docs=False)
|
|
||||||
car_params = car_params.as_reader()
|
|
||||||
car_interface = CarInterface(car_params, car_params_sp)
|
|
||||||
sunnypilot_interfaces.setup_interfaces(car_interface)
|
sunnypilot_interfaces.setup_interfaces(car_interface)
|
||||||
assert car_params
|
|
||||||
assert car_params_sp
|
|
||||||
assert car_interface
|
|
||||||
|
|
||||||
assert car_params.mass > 1
|
|
||||||
assert car_params.wheelbase > 0
|
|
||||||
# centerToFront is center of gravity to front wheels, assert a reasonable range
|
|
||||||
assert car_params.wheelbase * 0.3 < car_params.centerToFront < car_params.wheelbase * 0.7
|
|
||||||
assert car_params.maxLateralAccel > 0
|
|
||||||
|
|
||||||
# Longitudinal sanity checks
|
|
||||||
assert len(car_params.longitudinalTuning.kpV) == len(car_params.longitudinalTuning.kpBP)
|
|
||||||
assert len(car_params.longitudinalTuning.kiV) == len(car_params.longitudinalTuning.kiBP)
|
|
||||||
|
|
||||||
# Lateral sanity checks
|
|
||||||
if car_params.steerControlType != CarParams.SteerControlType.angle:
|
|
||||||
tune = car_params.lateralTuning
|
|
||||||
if tune.which() == 'pid':
|
|
||||||
if car_name != MOCK.MOCK:
|
|
||||||
assert not math.isnan(tune.pid.kf) and tune.pid.kf > 0
|
|
||||||
assert len(tune.pid.kpV) > 0 and len(tune.pid.kpV) == len(tune.pid.kpBP)
|
|
||||||
assert len(tune.pid.kiV) > 0 and len(tune.pid.kiV) == len(tune.pid.kiBP)
|
|
||||||
|
|
||||||
elif tune.which() == 'torque':
|
|
||||||
assert not math.isnan(tune.torque.kf) and tune.torque.kf > 0
|
|
||||||
assert not math.isnan(tune.torque.friction) and tune.torque.friction > 0
|
|
||||||
|
|
||||||
cc_msg = FuzzyGenerator.get_random_msg(data.draw, car.CarControl, real_floats=True)
|
cc_msg = FuzzyGenerator.get_random_msg(data.draw, car.CarControl, real_floats=True)
|
||||||
cc_sp_msg = FuzzyGenerator.get_random_msg(data.draw, custom.CarControlSP, real_floats=True)
|
cc_sp_msg = FuzzyGenerator.get_random_msg(data.draw, custom.CarControlSP, real_floats=True)
|
||||||
@@ -101,7 +60,7 @@ class TestCarInterfaces:
|
|||||||
# Test controller initialization
|
# Test controller initialization
|
||||||
# TODO: wait until card refactor is merged to run controller a few times,
|
# TODO: wait until card refactor is merged to run controller a few times,
|
||||||
# hypothesis also slows down significantly with just one more message draw
|
# hypothesis also slows down significantly with just one more message draw
|
||||||
LongControl(car_params)
|
LongControl(car_params, car_params_sp)
|
||||||
if car_params.steerControlType == CarParams.SteerControlType.angle:
|
if car_params.steerControlType == CarParams.SteerControlType.angle:
|
||||||
LatControlAngle(car_params, car_params_sp, car_interface)
|
LatControlAngle(car_params, car_params_sp, car_interface)
|
||||||
elif car_params.lateralTuning.which() == 'pid':
|
elif car_params.lateralTuning.which() == 'pid':
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import numpy as np
|
|||||||
from parameterized import parameterized_class
|
from parameterized import parameterized_class
|
||||||
from cereal import log
|
from cereal import log
|
||||||
from openpilot.selfdrive.car.cruise import VCruiseHelper, V_CRUISE_MIN, V_CRUISE_MAX, V_CRUISE_INITIAL, IMPERIAL_INCREMENT
|
from openpilot.selfdrive.car.cruise import VCruiseHelper, V_CRUISE_MIN, V_CRUISE_MAX, V_CRUISE_INITIAL, IMPERIAL_INCREMENT
|
||||||
from cereal import car
|
from cereal import car, custom
|
||||||
from openpilot.common.constants import CV
|
from openpilot.common.constants import CV
|
||||||
from openpilot.selfdrive.test.longitudinal_maneuvers.maneuver import Maneuver
|
from openpilot.selfdrive.test.longitudinal_maneuvers.maneuver import Maneuver
|
||||||
|
|
||||||
@@ -44,12 +44,13 @@ class TestCruiseSpeed:
|
|||||||
assert simulation_steady_state == pytest.approx(cruise_speed, abs=.01), f'Did not reach {self.speed} m/s'
|
assert simulation_steady_state == pytest.approx(cruise_speed, abs=.01), f'Did not reach {self.speed} m/s'
|
||||||
|
|
||||||
|
|
||||||
# TODO: test pcmCruise
|
# TODO: test pcmCruise and pcmCruiseSpeed
|
||||||
@parameterized_class(('pcm_cruise',), [(False,)])
|
@parameterized_class(('pcm_cruise', 'pcm_cruise_speed'), [(False, True)])
|
||||||
class TestVCruiseHelper:
|
class TestVCruiseHelper:
|
||||||
def setup_method(self):
|
def setup_method(self):
|
||||||
self.CP = car.CarParams(pcmCruise=self.pcm_cruise)
|
self.CP = car.CarParams(pcmCruise=self.pcm_cruise)
|
||||||
self.v_cruise_helper = VCruiseHelper(self.CP)
|
self.CP_SP = custom.CarParamsSP(pcmCruiseSpeed=self.pcm_cruise_speed)
|
||||||
|
self.v_cruise_helper = VCruiseHelper(self.CP, self.CP_SP)
|
||||||
self.reset_cruise_speed_state()
|
self.reset_cruise_speed_state()
|
||||||
|
|
||||||
def reset_cruise_speed_state(self):
|
def reset_cruise_speed_state(self):
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ class Controls(ControlsExt, ModelStateBase):
|
|||||||
self.pose_calibrator = PoseCalibrator()
|
self.pose_calibrator = PoseCalibrator()
|
||||||
self.calibrated_pose: Pose | None = None
|
self.calibrated_pose: Pose | None = None
|
||||||
|
|
||||||
self.LoC = LongControl(self.CP)
|
self.LoC = LongControl(self.CP, self.CP_SP)
|
||||||
self.VM = VehicleModel(self.CP)
|
self.VM = VehicleModel(self.CP)
|
||||||
self.LaC: LatControl
|
self.LaC: LatControl
|
||||||
if self.CP.steerControlType == car.CarParams.SteerControlType.angle:
|
if self.CP.steerControlType == car.CarParams.SteerControlType.angle:
|
||||||
@@ -116,7 +116,8 @@ class Controls(ControlsExt, ModelStateBase):
|
|||||||
|
|
||||||
CC.latActive = _lat_active and not CS.steerFaultTemporary and not CS.steerFaultPermanent and \
|
CC.latActive = _lat_active and not CS.steerFaultTemporary and not CS.steerFaultPermanent and \
|
||||||
(not standstill or self.CP.steerAtStandstill)
|
(not standstill or self.CP.steerAtStandstill)
|
||||||
CC.longActive = CC.enabled and not any(e.overrideLongitudinal for e in self.sm['onroadEvents']) and self.CP.openpilotLongitudinalControl
|
CC.longActive = CC.enabled and not any(e.overrideLongitudinal for e in self.sm['onroadEvents']) and \
|
||||||
|
(self.CP.openpilotLongitudinalControl or not self.CP_SP.pcmCruiseSpeed)
|
||||||
|
|
||||||
actuators = CC.actuators
|
actuators = CC.actuators
|
||||||
actuators.longControlState = self.LoC.long_control_state
|
actuators.longControlState = self.LoC.long_control_state
|
||||||
@@ -168,7 +169,7 @@ class Controls(ControlsExt, ModelStateBase):
|
|||||||
CC.orientationNED = self.calibrated_pose.orientation.xyz.tolist()
|
CC.orientationNED = self.calibrated_pose.orientation.xyz.tolist()
|
||||||
CC.angularVelocity = self.calibrated_pose.angular_velocity.xyz.tolist()
|
CC.angularVelocity = self.calibrated_pose.angular_velocity.xyz.tolist()
|
||||||
|
|
||||||
CC.cruiseControl.override = CC.enabled and not CC.longActive and self.CP.openpilotLongitudinalControl
|
CC.cruiseControl.override = CC.enabled and not CC.longActive and (self.CP.openpilotLongitudinalControl or not self.CP_SP.pcmCruiseSpeed)
|
||||||
CC.cruiseControl.cancel = CS.cruiseState.enabled and (not CC.enabled or not self.CP.pcmCruise)
|
CC.cruiseControl.cancel = CS.cruiseState.enabled and (not CC.enabled or not self.CP.pcmCruise)
|
||||||
CC.cruiseControl.resume = CC.enabled and CS.cruiseState.standstill and not self.sm['longitudinalPlan'].shouldStop
|
CC.cruiseControl.resume = CC.enabled and CS.cruiseState.standstill and not self.sm['longitudinalPlan'].shouldStop
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,10 @@ class DesireHelper:
|
|||||||
self.lane_turn_controller = LaneTurnController(self)
|
self.lane_turn_controller = LaneTurnController(self)
|
||||||
self.lane_turn_direction = custom.TurnDirection.none
|
self.lane_turn_direction = custom.TurnDirection.none
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_lane_change_direction(CS):
|
||||||
|
return LaneChangeDirection.left if CS.leftBlinker else LaneChangeDirection.right
|
||||||
|
|
||||||
def update(self, carstate, lateral_active, lane_change_prob):
|
def update(self, carstate, lateral_active, lane_change_prob):
|
||||||
self.alc.update_params()
|
self.alc.update_params()
|
||||||
self.lane_turn_controller.update_params()
|
self.lane_turn_controller.update_params()
|
||||||
@@ -71,12 +75,13 @@ class DesireHelper:
|
|||||||
if self.lane_change_state == LaneChangeState.off and one_blinker and not self.prev_one_blinker and not below_lane_change_speed:
|
if self.lane_change_state == LaneChangeState.off and one_blinker and not self.prev_one_blinker and not below_lane_change_speed:
|
||||||
self.lane_change_state = LaneChangeState.preLaneChange
|
self.lane_change_state = LaneChangeState.preLaneChange
|
||||||
self.lane_change_ll_prob = 1.0
|
self.lane_change_ll_prob = 1.0
|
||||||
|
# Initialize lane change direction to prevent UI alert flicker
|
||||||
|
self.lane_change_direction = self.get_lane_change_direction(carstate)
|
||||||
|
|
||||||
# LaneChangeState.preLaneChange
|
# LaneChangeState.preLaneChange
|
||||||
elif self.lane_change_state == LaneChangeState.preLaneChange:
|
elif self.lane_change_state == LaneChangeState.preLaneChange:
|
||||||
# Set lane change direction
|
# Update lane change direction
|
||||||
self.lane_change_direction = LaneChangeDirection.left if \
|
self.lane_change_direction = self.get_lane_change_direction(carstate)
|
||||||
carstate.leftBlinker else LaneChangeDirection.right
|
|
||||||
|
|
||||||
torque_applied = carstate.steeringPressed and \
|
torque_applied = carstate.steeringPressed and \
|
||||||
((carstate.steeringTorque > 0 and self.lane_change_direction == LaneChangeDirection.left) or
|
((carstate.steeringTorque > 0 and self.lane_change_direction == LaneChangeDirection.left) or
|
||||||
|
|||||||
@@ -48,6 +48,10 @@ class LatControlTorque(LatControl):
|
|||||||
self.lateral_accel_from_torque(-self.steer_max, self.torque_params))
|
self.lateral_accel_from_torque(-self.steer_max, self.torque_params))
|
||||||
|
|
||||||
def update(self, active, CS, VM, params, steer_limited_by_safety, desired_curvature, calibrated_pose, curvature_limited):
|
def update(self, active, CS, VM, params, steer_limited_by_safety, desired_curvature, calibrated_pose, curvature_limited):
|
||||||
|
# Override torque params from extension
|
||||||
|
if self.extension.update_override_torque_params(self.torque_params):
|
||||||
|
self.update_limits()
|
||||||
|
|
||||||
pid_log = log.ControlsState.LateralTorqueState.new_message()
|
pid_log = log.ControlsState.LateralTorqueState.new_message()
|
||||||
if not active:
|
if not active:
|
||||||
output_torque = 0.0
|
output_torque = 0.0
|
||||||
@@ -56,10 +60,8 @@ class LatControlTorque(LatControl):
|
|||||||
actual_curvature = -VM.calc_curvature(math.radians(CS.steeringAngleDeg - params.angleOffsetDeg), CS.vEgo, params.roll)
|
actual_curvature = -VM.calc_curvature(math.radians(CS.steeringAngleDeg - params.angleOffsetDeg), CS.vEgo, params.roll)
|
||||||
roll_compensation = params.roll * ACCELERATION_DUE_TO_GRAVITY
|
roll_compensation = params.roll * ACCELERATION_DUE_TO_GRAVITY
|
||||||
curvature_deadzone = abs(VM.calc_curvature(math.radians(self.steering_angle_deadzone_deg), CS.vEgo, 0.0))
|
curvature_deadzone = abs(VM.calc_curvature(math.radians(self.steering_angle_deadzone_deg), CS.vEgo, 0.0))
|
||||||
desired_lateral_accel = desired_curvature * CS.vEgo ** 2
|
|
||||||
|
|
||||||
# desired rate is the desired rate of change in the setpoint, not the absolute desired curvature
|
desired_lateral_accel = desired_curvature * CS.vEgo ** 2
|
||||||
# desired_lateral_jerk = desired_curvature_rate * CS.vEgo ** 2
|
|
||||||
actual_lateral_accel = actual_curvature * CS.vEgo ** 2
|
actual_lateral_accel = actual_curvature * CS.vEgo ** 2
|
||||||
lateral_accel_deadzone = curvature_deadzone * CS.vEgo ** 2
|
lateral_accel_deadzone = curvature_deadzone * CS.vEgo ** 2
|
||||||
|
|
||||||
@@ -71,6 +73,8 @@ class LatControlTorque(LatControl):
|
|||||||
# do error correction in lateral acceleration space, convert at end to handle non-linear torque responses correctly
|
# do error correction in lateral acceleration space, convert at end to handle non-linear torque responses correctly
|
||||||
pid_log.error = float(setpoint - measurement)
|
pid_log.error = float(setpoint - measurement)
|
||||||
ff = gravity_adjusted_lateral_accel
|
ff = gravity_adjusted_lateral_accel
|
||||||
|
# latAccelOffset corrects roll compensation bias from device roll misalignment relative to car roll
|
||||||
|
ff -= self.torque_params.latAccelOffset
|
||||||
ff += get_friction(desired_lateral_accel - actual_lateral_accel, lateral_accel_deadzone, FRICTION_THRESHOLD, self.torque_params)
|
ff += get_friction(desired_lateral_accel - actual_lateral_accel, lateral_accel_deadzone, FRICTION_THRESHOLD, self.torque_params)
|
||||||
|
|
||||||
freeze_integrator = steer_limited_by_safety or CS.steeringPressed or CS.vEgo < 5
|
freeze_integrator = steer_limited_by_safety or CS.steeringPressed or CS.vEgo < 5
|
||||||
|
|||||||
@@ -10,8 +10,11 @@ CONTROL_N_T_IDX = ModelConstants.T_IDXS[:CONTROL_N]
|
|||||||
LongCtrlState = car.CarControl.Actuators.LongControlState
|
LongCtrlState = car.CarControl.Actuators.LongControlState
|
||||||
|
|
||||||
|
|
||||||
def long_control_state_trans(CP, active, long_control_state, v_ego,
|
def long_control_state_trans(CP, CP_SP, active, long_control_state, v_ego,
|
||||||
should_stop, brake_pressed, cruise_standstill):
|
should_stop, brake_pressed, cruise_standstill):
|
||||||
|
# Gas Interceptor
|
||||||
|
cruise_standstill = cruise_standstill and not CP_SP.enableGasInterceptor
|
||||||
|
|
||||||
stopping_condition = should_stop
|
stopping_condition = should_stop
|
||||||
starting_condition = (not should_stop and
|
starting_condition = (not should_stop and
|
||||||
not cruise_standstill and
|
not cruise_standstill and
|
||||||
@@ -45,8 +48,9 @@ def long_control_state_trans(CP, active, long_control_state, v_ego,
|
|||||||
return long_control_state
|
return long_control_state
|
||||||
|
|
||||||
class LongControl:
|
class LongControl:
|
||||||
def __init__(self, CP):
|
def __init__(self, CP, CP_SP):
|
||||||
self.CP = CP
|
self.CP = CP
|
||||||
|
self.CP_SP = CP_SP
|
||||||
self.long_control_state = LongCtrlState.off
|
self.long_control_state = LongCtrlState.off
|
||||||
self.pid = PIDController((CP.longitudinalTuning.kpBP, CP.longitudinalTuning.kpV),
|
self.pid = PIDController((CP.longitudinalTuning.kpBP, CP.longitudinalTuning.kpV),
|
||||||
(CP.longitudinalTuning.kiBP, CP.longitudinalTuning.kiV),
|
(CP.longitudinalTuning.kiBP, CP.longitudinalTuning.kiV),
|
||||||
@@ -61,7 +65,7 @@ class LongControl:
|
|||||||
self.pid.neg_limit = accel_limits[0]
|
self.pid.neg_limit = accel_limits[0]
|
||||||
self.pid.pos_limit = accel_limits[1]
|
self.pid.pos_limit = accel_limits[1]
|
||||||
|
|
||||||
self.long_control_state = long_control_state_trans(self.CP, active, self.long_control_state, CS.vEgo,
|
self.long_control_state = long_control_state_trans(self.CP, self.CP_SP, active, self.long_control_state, CS.vEgo,
|
||||||
should_stop, CS.brakePressed,
|
should_stop, CS.brakePressed,
|
||||||
CS.cruiseState.standstill)
|
CS.cruiseState.standstill)
|
||||||
if self.long_control_state == LongCtrlState.off:
|
if self.long_control_state == LongCtrlState.off:
|
||||||
|
|||||||
@@ -146,6 +146,9 @@ class LongitudinalPlanner(LongitudinalPlannerSP):
|
|||||||
clipped_accel_coast_interp = np.interp(v_ego, [MIN_ALLOW_THROTTLE_SPEED, MIN_ALLOW_THROTTLE_SPEED*2], [accel_clip[1], clipped_accel_coast])
|
clipped_accel_coast_interp = np.interp(v_ego, [MIN_ALLOW_THROTTLE_SPEED, MIN_ALLOW_THROTTLE_SPEED*2], [accel_clip[1], clipped_accel_coast])
|
||||||
accel_clip[1] = min(accel_clip[1], clipped_accel_coast_interp)
|
accel_clip[1] = min(accel_clip[1], clipped_accel_coast_interp)
|
||||||
|
|
||||||
|
# Get new v_cruise and a_desired from Smart Cruise Control and Speed Limit Assist
|
||||||
|
v_cruise, self.a_desired = LongitudinalPlannerSP.update_targets(self, sm, self.v_desired_filter.x, self.a_desired, v_cruise)
|
||||||
|
|
||||||
if force_slow_decel:
|
if force_slow_decel:
|
||||||
v_cruise = 0.0
|
v_cruise = 0.0
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from cereal import car
|
from cereal import car
|
||||||
|
from openpilot.common.gps import get_gps_location_service
|
||||||
from openpilot.common.params import Params
|
from openpilot.common.params import Params
|
||||||
from openpilot.common.realtime import Priority, config_realtime_process
|
from openpilot.common.realtime import Priority, config_realtime_process
|
||||||
from openpilot.common.swaglog import cloudlog
|
from openpilot.common.swaglog import cloudlog
|
||||||
@@ -16,14 +17,18 @@ def main():
|
|||||||
CP = messaging.log_from_bytes(params.get("CarParams", block=True), car.CarParams)
|
CP = messaging.log_from_bytes(params.get("CarParams", block=True), car.CarParams)
|
||||||
cloudlog.info("plannerd got CarParams: %s", CP.brand)
|
cloudlog.info("plannerd got CarParams: %s", CP.brand)
|
||||||
|
|
||||||
|
gps_location_service = get_gps_location_service(params)
|
||||||
|
|
||||||
ldw = LaneDepartureWarning()
|
ldw = LaneDepartureWarning()
|
||||||
longitudinal_planner = LongitudinalPlanner(CP)
|
longitudinal_planner = LongitudinalPlanner(CP)
|
||||||
pm = messaging.PubMaster(['longitudinalPlan', 'driverAssistance', 'longitudinalPlanSP'])
|
pm = messaging.PubMaster(['longitudinalPlan', 'driverAssistance', 'longitudinalPlanSP'])
|
||||||
sm = messaging.SubMaster(['carControl', 'carState', 'controlsState', 'liveParameters', 'radarState', 'modelV2', 'selfdriveState'],
|
sm = messaging.SubMaster(['carControl', 'carState', 'controlsState', 'liveParameters', 'radarState', 'modelV2', 'selfdriveState',
|
||||||
poll='modelV2')
|
'liveMapDataSP', 'carStateSP', gps_location_service],
|
||||||
|
poll='carState')
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
sm.update()
|
sm.update()
|
||||||
|
longitudinal_planner.sla.update_car_state(sm['carState'])
|
||||||
if sm.updated['modelV2']:
|
if sm.updated['modelV2']:
|
||||||
longitudinal_planner.update(sm)
|
longitudinal_planner.update(sm)
|
||||||
longitudinal_planner.publish(sm, pm)
|
longitudinal_planner.publish(sm, pm)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from cereal import car
|
from cereal import car, custom
|
||||||
from openpilot.selfdrive.controls.lib.longcontrol import LongCtrlState, long_control_state_trans
|
from openpilot.selfdrive.controls.lib.longcontrol import LongCtrlState, long_control_state_trans
|
||||||
|
|
||||||
|
|
||||||
@@ -8,49 +8,52 @@ class TestLongControlStateTransition:
|
|||||||
|
|
||||||
def test_stay_stopped(self):
|
def test_stay_stopped(self):
|
||||||
CP = car.CarParams.new_message()
|
CP = car.CarParams.new_message()
|
||||||
|
CP_SP = custom.CarParamsSP.new_message()
|
||||||
active = True
|
active = True
|
||||||
current_state = LongCtrlState.stopping
|
current_state = LongCtrlState.stopping
|
||||||
next_state = long_control_state_trans(CP, active, current_state, v_ego=0.1,
|
next_state = long_control_state_trans(CP, CP_SP, active, current_state, v_ego=0.1,
|
||||||
should_stop=True, brake_pressed=False, cruise_standstill=False)
|
should_stop=True, brake_pressed=False, cruise_standstill=False)
|
||||||
assert next_state == LongCtrlState.stopping
|
assert next_state == LongCtrlState.stopping
|
||||||
next_state = long_control_state_trans(CP, active, current_state, v_ego=0.1,
|
next_state = long_control_state_trans(CP, CP_SP, active, current_state, v_ego=0.1,
|
||||||
should_stop=False, brake_pressed=True, cruise_standstill=False)
|
should_stop=False, brake_pressed=True, cruise_standstill=False)
|
||||||
assert next_state == LongCtrlState.stopping
|
assert next_state == LongCtrlState.stopping
|
||||||
next_state = long_control_state_trans(CP, active, current_state, v_ego=0.1,
|
next_state = long_control_state_trans(CP, CP_SP, active, current_state, v_ego=0.1,
|
||||||
should_stop=False, brake_pressed=False, cruise_standstill=True)
|
should_stop=False, brake_pressed=False, cruise_standstill=True)
|
||||||
assert next_state == LongCtrlState.stopping
|
assert next_state == LongCtrlState.stopping
|
||||||
next_state = long_control_state_trans(CP, active, current_state, v_ego=1.0,
|
next_state = long_control_state_trans(CP, CP_SP, active, current_state, v_ego=1.0,
|
||||||
should_stop=False, brake_pressed=False, cruise_standstill=False)
|
should_stop=False, brake_pressed=False, cruise_standstill=False)
|
||||||
assert next_state == LongCtrlState.pid
|
assert next_state == LongCtrlState.pid
|
||||||
active = False
|
active = False
|
||||||
next_state = long_control_state_trans(CP, active, current_state, v_ego=1.0,
|
next_state = long_control_state_trans(CP, CP_SP, active, current_state, v_ego=1.0,
|
||||||
should_stop=False, brake_pressed=False, cruise_standstill=False)
|
should_stop=False, brake_pressed=False, cruise_standstill=False)
|
||||||
assert next_state == LongCtrlState.off
|
assert next_state == LongCtrlState.off
|
||||||
|
|
||||||
def test_engage():
|
def test_engage():
|
||||||
CP = car.CarParams.new_message()
|
CP = car.CarParams.new_message()
|
||||||
|
CP_SP = custom.CarParamsSP.new_message()
|
||||||
active = True
|
active = True
|
||||||
current_state = LongCtrlState.off
|
current_state = LongCtrlState.off
|
||||||
next_state = long_control_state_trans(CP, active, current_state, v_ego=0.1,
|
next_state = long_control_state_trans(CP, CP_SP, active, current_state, v_ego=0.1,
|
||||||
should_stop=True, brake_pressed=False, cruise_standstill=False)
|
should_stop=True, brake_pressed=False, cruise_standstill=False)
|
||||||
assert next_state == LongCtrlState.stopping
|
assert next_state == LongCtrlState.stopping
|
||||||
next_state = long_control_state_trans(CP, active, current_state, v_ego=0.1,
|
next_state = long_control_state_trans(CP, CP_SP, active, current_state, v_ego=0.1,
|
||||||
should_stop=False, brake_pressed=True, cruise_standstill=False)
|
should_stop=False, brake_pressed=True, cruise_standstill=False)
|
||||||
assert next_state == LongCtrlState.stopping
|
assert next_state == LongCtrlState.stopping
|
||||||
next_state = long_control_state_trans(CP, active, current_state, v_ego=0.1,
|
next_state = long_control_state_trans(CP, CP_SP, active, current_state, v_ego=0.1,
|
||||||
should_stop=False, brake_pressed=False, cruise_standstill=True)
|
should_stop=False, brake_pressed=False, cruise_standstill=True)
|
||||||
assert next_state == LongCtrlState.stopping
|
assert next_state == LongCtrlState.stopping
|
||||||
next_state = long_control_state_trans(CP, active, current_state, v_ego=0.1,
|
next_state = long_control_state_trans(CP, CP_SP, active, current_state, v_ego=0.1,
|
||||||
should_stop=False, brake_pressed=False, cruise_standstill=False)
|
should_stop=False, brake_pressed=False, cruise_standstill=False)
|
||||||
assert next_state == LongCtrlState.pid
|
assert next_state == LongCtrlState.pid
|
||||||
|
|
||||||
def test_starting():
|
def test_starting():
|
||||||
CP = car.CarParams.new_message(startingState=True, vEgoStarting=0.5)
|
CP = car.CarParams.new_message(startingState=True, vEgoStarting=0.5)
|
||||||
|
CP_SP = custom.CarParamsSP.new_message()
|
||||||
active = True
|
active = True
|
||||||
current_state = LongCtrlState.starting
|
current_state = LongCtrlState.starting
|
||||||
next_state = long_control_state_trans(CP, active, current_state, v_ego=0.1,
|
next_state = long_control_state_trans(CP, CP_SP, active, current_state, v_ego=0.1,
|
||||||
should_stop=False, brake_pressed=False, cruise_standstill=False)
|
should_stop=False, brake_pressed=False, cruise_standstill=False)
|
||||||
assert next_state == LongCtrlState.starting
|
assert next_state == LongCtrlState.starting
|
||||||
next_state = long_control_state_trans(CP, active, current_state, v_ego=1.0,
|
next_state = long_control_state_trans(CP, CP_SP, active, current_state, v_ego=1.0,
|
||||||
should_stop=False, brake_pressed=False, cruise_standstill=False)
|
should_stop=False, brake_pressed=False, cruise_standstill=False)
|
||||||
assert next_state == LongCtrlState.pid
|
assert next_state == LongCtrlState.pid
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
import numpy as np
|
||||||
|
from cereal import car, messaging
|
||||||
|
from opendbc.car import ACCELERATION_DUE_TO_GRAVITY
|
||||||
|
from opendbc.car import structs
|
||||||
|
from opendbc.car.lateral import get_friction, FRICTION_THRESHOLD
|
||||||
|
from openpilot.common.realtime import DT_MDL
|
||||||
|
from openpilot.selfdrive.locationd.torqued import TorqueEstimator, MIN_BUCKET_POINTS, POINTS_PER_BUCKET, STEER_BUCKET_BOUNDS
|
||||||
|
|
||||||
|
np.random.seed(0)
|
||||||
|
|
||||||
|
LA_ERR_STD = 1.0
|
||||||
|
INPUT_NOISE_STD = 0.08
|
||||||
|
V_EGO = 30.0
|
||||||
|
|
||||||
|
WARMUP_BUCKET_POINTS = (1.5*MIN_BUCKET_POINTS).astype(int)
|
||||||
|
STRAIGHT_ROAD_LA_BOUNDS = (0.02, 0.03)
|
||||||
|
|
||||||
|
ROLL_BIAS_DEG = 2.0
|
||||||
|
ROLL_COMPENSATION_BIAS = ACCELERATION_DUE_TO_GRAVITY*float(np.sin(np.deg2rad(ROLL_BIAS_DEG)))
|
||||||
|
TORQUE_TUNE = structs.CarParams.LateralTorqueTuning(latAccelFactor=2.0, latAccelOffset=0.0, friction=0.2)
|
||||||
|
TORQUE_TUNE_BIASED = structs.CarParams.LateralTorqueTuning(latAccelFactor=2.0, latAccelOffset=-ROLL_COMPENSATION_BIAS, friction=0.2)
|
||||||
|
|
||||||
|
def generate_inputs(torque_tune, la_err_std, input_noise_std=None):
|
||||||
|
rng = np.random.default_rng(0)
|
||||||
|
steer_torques = np.concat([rng.uniform(bnd[0], bnd[1], pts) for bnd, pts in zip(STEER_BUCKET_BOUNDS, WARMUP_BUCKET_POINTS, strict=True)])
|
||||||
|
la_errs = rng.normal(scale=la_err_std, size=steer_torques.size)
|
||||||
|
frictions = np.array([get_friction(la_err, 0.0, FRICTION_THRESHOLD, torque_tune) for la_err in la_errs])
|
||||||
|
lat_accels = torque_tune.latAccelFactor*steer_torques + torque_tune.latAccelOffset + frictions
|
||||||
|
if input_noise_std is not None:
|
||||||
|
steer_torques += rng.normal(scale=input_noise_std, size=steer_torques.size)
|
||||||
|
lat_accels += rng.normal(scale=input_noise_std, size=steer_torques.size)
|
||||||
|
return steer_torques, lat_accels
|
||||||
|
|
||||||
|
def get_warmed_up_estimator(steer_torques, lat_accels):
|
||||||
|
est = TorqueEstimator(car.CarParams())
|
||||||
|
for steer_torque, lat_accel in zip(steer_torques, lat_accels, strict=True):
|
||||||
|
est.filtered_points.add_point(steer_torque, lat_accel)
|
||||||
|
return est
|
||||||
|
|
||||||
|
def simulate_straight_road_msgs(est):
|
||||||
|
carControl = messaging.new_message('carControl').carControl
|
||||||
|
carOutput = messaging.new_message('carOutput').carOutput
|
||||||
|
carState = messaging.new_message('carState').carState
|
||||||
|
livePose = messaging.new_message('livePose').livePose
|
||||||
|
carControl.latActive = True
|
||||||
|
carState.vEgo = V_EGO
|
||||||
|
carState.steeringPressed = False
|
||||||
|
ts = DT_MDL*np.arange(2*POINTS_PER_BUCKET)
|
||||||
|
steer_torques = np.concat((np.linspace(-0.03, -0.02, POINTS_PER_BUCKET), np.linspace(0.02, 0.03, POINTS_PER_BUCKET)))
|
||||||
|
lat_accels = TORQUE_TUNE.latAccelFactor * steer_torques
|
||||||
|
for t, steer_torque, lat_accel in zip(ts, steer_torques, lat_accels, strict=True):
|
||||||
|
carOutput.actuatorsOutput.torque = float(-steer_torque)
|
||||||
|
livePose.orientationNED.x = float(np.deg2rad(ROLL_BIAS_DEG))
|
||||||
|
livePose.angularVelocityDevice.z = float(lat_accel / V_EGO)
|
||||||
|
for which, msg in (('carControl', carControl), ('carOutput', carOutput), ('carState', carState), ('livePose', livePose)):
|
||||||
|
est.handle_log(t, which, msg)
|
||||||
|
|
||||||
|
def test_estimated_offset():
|
||||||
|
steer_torques, lat_accels = generate_inputs(TORQUE_TUNE_BIASED, la_err_std=LA_ERR_STD, input_noise_std=INPUT_NOISE_STD)
|
||||||
|
est = get_warmed_up_estimator(steer_torques, lat_accels)
|
||||||
|
msg = est.get_msg()
|
||||||
|
# TODO add lataccelfactor and friction check when we have more accurate estimates
|
||||||
|
assert abs(msg.liveTorqueParameters.latAccelOffsetRaw - TORQUE_TUNE_BIASED.latAccelOffset) < 0.1
|
||||||
|
|
||||||
|
def test_straight_road_roll_bias():
|
||||||
|
steer_torques, lat_accels = generate_inputs(TORQUE_TUNE, la_err_std=LA_ERR_STD, input_noise_std=INPUT_NOISE_STD)
|
||||||
|
est = get_warmed_up_estimator(steer_torques, lat_accels)
|
||||||
|
simulate_straight_road_msgs(est)
|
||||||
|
msg = est.get_msg()
|
||||||
|
assert (msg.liveTorqueParameters.latAccelOffsetRaw < -0.05) and np.isfinite(msg.liveTorqueParameters.latAccelOffsetRaw)
|
||||||
@@ -11,6 +11,7 @@ from openpilot.common.filter_simple import FirstOrderFilter
|
|||||||
from openpilot.common.swaglog import cloudlog
|
from openpilot.common.swaglog import cloudlog
|
||||||
from openpilot.selfdrive.locationd.helpers import PointBuckets, ParameterEstimator, PoseCalibrator, Pose
|
from openpilot.selfdrive.locationd.helpers import PointBuckets, ParameterEstimator, PoseCalibrator, Pose
|
||||||
from openpilot.sunnypilot.livedelay.helpers import get_lat_delay
|
from openpilot.sunnypilot.livedelay.helpers import get_lat_delay
|
||||||
|
from openpilot.sunnypilot.selfdrive.locationd.torqued_ext import TorqueEstimatorExt
|
||||||
|
|
||||||
HISTORY = 5 # secs
|
HISTORY = 5 # secs
|
||||||
POINTS_PER_BUCKET = 1500
|
POINTS_PER_BUCKET = 1500
|
||||||
@@ -50,9 +51,10 @@ class TorqueBuckets(PointBuckets):
|
|||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
class TorqueEstimator(ParameterEstimator):
|
class TorqueEstimator(ParameterEstimator, TorqueEstimatorExt):
|
||||||
def __init__(self, CP, decimated=False, track_all_points=False):
|
def __init__(self, CP, decimated=False, track_all_points=False):
|
||||||
super().__init__()
|
ParameterEstimator.__init__(self)
|
||||||
|
TorqueEstimatorExt.__init__(self, CP)
|
||||||
self.CP = CP
|
self.CP = CP
|
||||||
self.hist_len = int(HISTORY / DT_MDL)
|
self.hist_len = int(HISTORY / DT_MDL)
|
||||||
self.lag = 0.0
|
self.lag = 0.0
|
||||||
@@ -82,6 +84,8 @@ class TorqueEstimator(ParameterEstimator):
|
|||||||
|
|
||||||
self.calibrator = PoseCalibrator()
|
self.calibrator = PoseCalibrator()
|
||||||
|
|
||||||
|
TorqueEstimatorExt.initialize_custom_params(self, decimated)
|
||||||
|
|
||||||
self.reset()
|
self.reset()
|
||||||
|
|
||||||
initial_params = {
|
initial_params = {
|
||||||
@@ -260,6 +264,8 @@ def main(demo=False):
|
|||||||
t = sm.logMonoTime[which] * 1e-9
|
t = sm.logMonoTime[which] * 1e-9
|
||||||
estimator.handle_log(t, which, sm[which])
|
estimator.handle_log(t, which, sm[which])
|
||||||
|
|
||||||
|
TorqueEstimatorExt.update_use_params(estimator)
|
||||||
|
|
||||||
# 4Hz driven by livePose
|
# 4Hz driven by livePose
|
||||||
if sm.frame % 5 == 0:
|
if sm.frame % 5 == 0:
|
||||||
pm.send('liveTorqueParameters', estimator.get_msg(valid=sm.all_checks()))
|
pm.send('liveTorqueParameters', estimator.get_msg(valid=sm.all_checks()))
|
||||||
|
|||||||
@@ -13,12 +13,9 @@ class ModelConstants:
|
|||||||
META_T_IDXS = [2., 4., 6., 8., 10.]
|
META_T_IDXS = [2., 4., 6., 8., 10.]
|
||||||
|
|
||||||
# model inputs constants
|
# model inputs constants
|
||||||
MODEL_FREQ = 20
|
N_FRAMES = 2
|
||||||
HISTORY_FREQ = 5
|
MODEL_RUN_FREQ = 20
|
||||||
HISTORY_LEN_SECONDS = 5
|
MODEL_CONTEXT_FREQ = 5 # "model_trained_fps"
|
||||||
TEMPORAL_SKIP = MODEL_FREQ // HISTORY_FREQ
|
|
||||||
FULL_HISTORY_BUFFER_LEN = MODEL_FREQ * HISTORY_LEN_SECONDS
|
|
||||||
INPUT_HISTORY_BUFFER_LEN = HISTORY_FREQ * HISTORY_LEN_SECONDS
|
|
||||||
|
|
||||||
FEATURE_LEN = 512
|
FEATURE_LEN = 512
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import capnp
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
from cereal import log
|
from cereal import log
|
||||||
from openpilot.selfdrive.modeld.constants import ModelConstants, Plan, Meta
|
from openpilot.selfdrive.modeld.constants import ModelConstants, Plan, Meta
|
||||||
|
from openpilot.sunnypilot.models.helpers import plan_x_idxs_helper
|
||||||
|
|
||||||
SEND_RAW_PRED = os.getenv('SEND_RAW_PRED')
|
SEND_RAW_PRED = os.getenv('SEND_RAW_PRED')
|
||||||
|
|
||||||
@@ -95,8 +96,8 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D
|
|||||||
# action
|
# action
|
||||||
modelV2.action = action
|
modelV2.action = action
|
||||||
|
|
||||||
# times at X_IDXS of edges and lines aren't used
|
# times at X_IDXS of edges and lines
|
||||||
LINE_T_IDXS: list[float] = []
|
LINE_T_IDXS: list[float] = plan_x_idxs_helper(ModelConstants, Plan, net_output_data)
|
||||||
|
|
||||||
# lane lines
|
# lane lines
|
||||||
modelV2.init('laneLines', 4)
|
modelV2.init('laneLines', 4)
|
||||||
@@ -149,7 +150,7 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D
|
|||||||
meta.hardBrakePredicted = hard_brake_predicted.item()
|
meta.hardBrakePredicted = hard_brake_predicted.item()
|
||||||
|
|
||||||
# confidence
|
# confidence
|
||||||
if vipc_frame_id % (2*ModelConstants.MODEL_FREQ) == 0:
|
if vipc_frame_id % (2*ModelConstants.MODEL_RUN_FREQ) == 0:
|
||||||
# any disengage prob
|
# any disengage prob
|
||||||
brake_disengage_probs = net_output_data['meta'][0,Meta.BRAKE_DISENGAGE]
|
brake_disengage_probs = net_output_data['meta'][0,Meta.BRAKE_DISENGAGE]
|
||||||
gas_disengage_probs = net_output_data['meta'][0,Meta.GAS_DISENGAGE]
|
gas_disengage_probs = net_output_data['meta'][0,Meta.GAS_DISENGAGE]
|
||||||
|
|||||||
+73
-23
@@ -80,6 +80,64 @@ class FrameMeta:
|
|||||||
if vipc is not None:
|
if vipc is not None:
|
||||||
self.frame_id, self.timestamp_sof, self.timestamp_eof = vipc.frame_id, vipc.timestamp_sof, vipc.timestamp_eof
|
self.frame_id, self.timestamp_sof, self.timestamp_eof = vipc.frame_id, vipc.timestamp_sof, vipc.timestamp_eof
|
||||||
|
|
||||||
|
class InputQueues:
|
||||||
|
def __init__ (self, model_fps, env_fps, n_frames_input):
|
||||||
|
assert env_fps % model_fps == 0
|
||||||
|
assert env_fps >= model_fps
|
||||||
|
self.model_fps = model_fps
|
||||||
|
self.env_fps = env_fps
|
||||||
|
self.n_frames_input = n_frames_input
|
||||||
|
|
||||||
|
self.dtypes = {}
|
||||||
|
self.shapes = {}
|
||||||
|
self.q = {}
|
||||||
|
|
||||||
|
def update_dtypes_and_shapes(self, input_dtypes, input_shapes) -> None:
|
||||||
|
self.dtypes.update(input_dtypes)
|
||||||
|
if self.env_fps == self.model_fps:
|
||||||
|
self.shapes.update(input_shapes)
|
||||||
|
else:
|
||||||
|
for k in input_shapes:
|
||||||
|
shape = list(input_shapes[k])
|
||||||
|
if 'img' in k:
|
||||||
|
n_channels = shape[1] // self.n_frames_input
|
||||||
|
shape[1] = (self.env_fps // self.model_fps + (self.n_frames_input - 1)) * n_channels
|
||||||
|
else:
|
||||||
|
shape[1] = (self.env_fps // self.model_fps) * shape[1]
|
||||||
|
self.shapes[k] = tuple(shape)
|
||||||
|
|
||||||
|
def reset(self) -> None:
|
||||||
|
self.q = {k: np.zeros(self.shapes[k], dtype=self.dtypes[k]) for k in self.dtypes.keys()}
|
||||||
|
|
||||||
|
def enqueue(self, inputs:dict[str, np.ndarray]) -> None:
|
||||||
|
for k in inputs.keys():
|
||||||
|
if inputs[k].dtype != self.dtypes[k]:
|
||||||
|
raise ValueError(f'supplied input <{k}({inputs[k].dtype})> has wrong dtype, expected {self.dtypes[k]}')
|
||||||
|
input_shape = list(self.shapes[k])
|
||||||
|
input_shape[1] = -1
|
||||||
|
single_input = inputs[k].reshape(tuple(input_shape))
|
||||||
|
sz = single_input.shape[1]
|
||||||
|
self.q[k][:,:-sz] = self.q[k][:,sz:]
|
||||||
|
self.q[k][:,-sz:] = single_input
|
||||||
|
|
||||||
|
def get(self, *names) -> dict[str, np.ndarray]:
|
||||||
|
if self.env_fps == self.model_fps:
|
||||||
|
return {k: self.q[k] for k in names}
|
||||||
|
else:
|
||||||
|
out = {}
|
||||||
|
for k in names:
|
||||||
|
shape = self.shapes[k]
|
||||||
|
if 'img' in k:
|
||||||
|
n_channels = shape[1] // (self.env_fps // self.model_fps + (self.n_frames_input - 1))
|
||||||
|
out[k] = np.concatenate([self.q[k][:, s:s+n_channels] for s in np.linspace(0, shape[1] - n_channels, self.n_frames_input, dtype=int)], axis=1)
|
||||||
|
elif 'pulse' in k:
|
||||||
|
# any pulse within interval counts
|
||||||
|
out[k] = self.q[k].reshape((shape[0], shape[1] * self.model_fps // self.env_fps, self.env_fps // self.model_fps, -1)).max(axis=2)
|
||||||
|
else:
|
||||||
|
idxs = np.arange(-1, -shape[1], -self.env_fps // self.model_fps)[::-1]
|
||||||
|
out[k] = self.q[k][:, idxs]
|
||||||
|
return out
|
||||||
|
|
||||||
class ModelState(ModelStateBase):
|
class ModelState(ModelStateBase):
|
||||||
frames: dict[str, DrivingModelFrame]
|
frames: dict[str, DrivingModelFrame]
|
||||||
inputs: dict[str, np.ndarray]
|
inputs: dict[str, np.ndarray]
|
||||||
@@ -102,19 +160,15 @@ class ModelState(ModelStateBase):
|
|||||||
self.policy_output_slices = policy_metadata['output_slices']
|
self.policy_output_slices = policy_metadata['output_slices']
|
||||||
policy_output_size = policy_metadata['output_shapes']['outputs'][1]
|
policy_output_size = policy_metadata['output_shapes']['outputs'][1]
|
||||||
|
|
||||||
self.frames = {name: DrivingModelFrame(context, ModelConstants.TEMPORAL_SKIP) for name in self.vision_input_names}
|
self.frames = {name: DrivingModelFrame(context, ModelConstants.MODEL_RUN_FREQ//ModelConstants.MODEL_CONTEXT_FREQ) for name in self.vision_input_names}
|
||||||
self.prev_desire = np.zeros(ModelConstants.DESIRE_LEN, dtype=np.float32)
|
self.prev_desire = np.zeros(ModelConstants.DESIRE_LEN, dtype=np.float32)
|
||||||
|
|
||||||
self.full_features_buffer = np.zeros((1, ModelConstants.FULL_HISTORY_BUFFER_LEN, ModelConstants.FEATURE_LEN), dtype=np.float32)
|
|
||||||
self.full_desire = np.zeros((1, ModelConstants.FULL_HISTORY_BUFFER_LEN, ModelConstants.DESIRE_LEN), dtype=np.float32)
|
|
||||||
self.temporal_idxs = slice(-1-(ModelConstants.TEMPORAL_SKIP*(ModelConstants.INPUT_HISTORY_BUFFER_LEN-1)), None, ModelConstants.TEMPORAL_SKIP)
|
|
||||||
|
|
||||||
# policy inputs
|
# policy inputs
|
||||||
self.numpy_inputs = {
|
self.numpy_inputs = {k: np.zeros(self.policy_input_shapes[k], dtype=np.float32) for k in self.policy_input_shapes}
|
||||||
'desire': np.zeros((1, ModelConstants.INPUT_HISTORY_BUFFER_LEN, ModelConstants.DESIRE_LEN), dtype=np.float32),
|
self.full_input_queues = InputQueues(ModelConstants.MODEL_CONTEXT_FREQ, ModelConstants.MODEL_RUN_FREQ, ModelConstants.N_FRAMES)
|
||||||
'traffic_convention': np.zeros((1, ModelConstants.TRAFFIC_CONVENTION_LEN), dtype=np.float32),
|
for k in ['desire_pulse', 'features_buffer']:
|
||||||
'features_buffer': np.zeros((1, ModelConstants.INPUT_HISTORY_BUFFER_LEN, ModelConstants.FEATURE_LEN), dtype=np.float32),
|
self.full_input_queues.update_dtypes_and_shapes({k: self.numpy_inputs[k].dtype}, {k: self.numpy_inputs[k].shape})
|
||||||
}
|
self.full_input_queues.reset()
|
||||||
|
|
||||||
# img buffers are managed in openCL transform code
|
# img buffers are managed in openCL transform code
|
||||||
self.vision_inputs: dict[str, Tensor] = {}
|
self.vision_inputs: dict[str, Tensor] = {}
|
||||||
@@ -136,15 +190,10 @@ class ModelState(ModelStateBase):
|
|||||||
def run(self, bufs: dict[str, VisionBuf], transforms: dict[str, np.ndarray],
|
def run(self, bufs: dict[str, VisionBuf], transforms: dict[str, np.ndarray],
|
||||||
inputs: dict[str, np.ndarray], prepare_only: bool) -> dict[str, np.ndarray] | None:
|
inputs: dict[str, np.ndarray], prepare_only: bool) -> dict[str, np.ndarray] | None:
|
||||||
# Model decides when action is completed, so desire input is just a pulse triggered on rising edge
|
# Model decides when action is completed, so desire input is just a pulse triggered on rising edge
|
||||||
inputs['desire'][0] = 0
|
inputs['desire_pulse'][0] = 0
|
||||||
new_desire = np.where(inputs['desire'] - self.prev_desire > .99, inputs['desire'], 0)
|
new_desire = np.where(inputs['desire_pulse'] - self.prev_desire > .99, inputs['desire_pulse'], 0)
|
||||||
self.prev_desire[:] = inputs['desire']
|
self.prev_desire[:] = inputs['desire_pulse']
|
||||||
|
|
||||||
self.full_desire[0,:-1] = self.full_desire[0,1:]
|
|
||||||
self.full_desire[0,-1] = new_desire
|
|
||||||
self.numpy_inputs['desire'][:] = self.full_desire.reshape((1,ModelConstants.INPUT_HISTORY_BUFFER_LEN,ModelConstants.TEMPORAL_SKIP,-1)).max(axis=2)
|
|
||||||
|
|
||||||
self.numpy_inputs['traffic_convention'][:] = inputs['traffic_convention']
|
|
||||||
imgs_cl = {name: self.frames[name].prepare(bufs[name], transforms[name].flatten()) for name in self.vision_input_names}
|
imgs_cl = {name: self.frames[name].prepare(bufs[name], transforms[name].flatten()) for name in self.vision_input_names}
|
||||||
|
|
||||||
if TICI and not USBGPU:
|
if TICI and not USBGPU:
|
||||||
@@ -163,9 +212,10 @@ class ModelState(ModelStateBase):
|
|||||||
self.vision_output = self.vision_run(**self.vision_inputs).contiguous().realize().uop.base.buffer.numpy()
|
self.vision_output = self.vision_run(**self.vision_inputs).contiguous().realize().uop.base.buffer.numpy()
|
||||||
vision_outputs_dict = self.parser.parse_vision_outputs(self.slice_outputs(self.vision_output, self.vision_output_slices))
|
vision_outputs_dict = self.parser.parse_vision_outputs(self.slice_outputs(self.vision_output, self.vision_output_slices))
|
||||||
|
|
||||||
self.full_features_buffer[0,:-1] = self.full_features_buffer[0,1:]
|
self.full_input_queues.enqueue({'features_buffer': vision_outputs_dict['hidden_state'], 'desire_pulse': new_desire})
|
||||||
self.full_features_buffer[0,-1] = vision_outputs_dict['hidden_state'][0, :]
|
for k in ['desire_pulse', 'features_buffer']:
|
||||||
self.numpy_inputs['features_buffer'][:] = self.full_features_buffer[0, self.temporal_idxs]
|
self.numpy_inputs[k][:] = self.full_input_queues.get(k)[k]
|
||||||
|
self.numpy_inputs['traffic_convention'][:] = inputs['traffic_convention']
|
||||||
|
|
||||||
self.policy_output = self.policy_run(**self.policy_inputs).contiguous().realize().uop.base.buffer.numpy()
|
self.policy_output = self.policy_run(**self.policy_inputs).contiguous().realize().uop.base.buffer.numpy()
|
||||||
policy_outputs_dict = self.parser.parse_policy_outputs(self.slice_outputs(self.policy_output, self.policy_output_slices))
|
policy_outputs_dict = self.parser.parse_policy_outputs(self.slice_outputs(self.policy_output, self.policy_output_slices))
|
||||||
@@ -223,7 +273,7 @@ def main(demo=False):
|
|||||||
params = Params()
|
params = Params()
|
||||||
|
|
||||||
# setup filter to track dropped frames
|
# setup filter to track dropped frames
|
||||||
frame_dropped_filter = FirstOrderFilter(0., 10., 1. / ModelConstants.MODEL_FREQ)
|
frame_dropped_filter = FirstOrderFilter(0., 10., 1. / ModelConstants.MODEL_RUN_FREQ)
|
||||||
frame_id = 0
|
frame_id = 0
|
||||||
last_vipc_frame_id = 0
|
last_vipc_frame_id = 0
|
||||||
run_count = 0
|
run_count = 0
|
||||||
@@ -320,7 +370,7 @@ def main(demo=False):
|
|||||||
bufs = {name: buf_extra if 'big' in name else buf_main for name in model.vision_input_names}
|
bufs = {name: buf_extra if 'big' in name else buf_main for name in model.vision_input_names}
|
||||||
transforms = {name: model_transform_extra if 'big' in name else model_transform_main for name in model.vision_input_names}
|
transforms = {name: model_transform_extra if 'big' in name else model_transform_main for name in model.vision_input_names}
|
||||||
inputs:dict[str, np.ndarray] = {
|
inputs:dict[str, np.ndarray] = {
|
||||||
'desire': vec_desire,
|
'desire_pulse': vec_desire,
|
||||||
'traffic_convention': traffic_convention,
|
'traffic_convention': traffic_convention,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:04b763fb71efe57a8a4c4168a8043ecd58939015026ded0dc755ded6905ac251
|
oid sha256:ebb38a934d6472c061cc6010f46d9720ca132d631a47e585a893bdd41ade2419
|
||||||
size 12343523
|
size 12343535
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:e66bb8d53eced3786ed71a59b55ffc6810944cb217f0518621cc76303260a1ef
|
oid sha256:befac016a247b7ad5dc5b55d339d127774ed7bd2b848f1583f72aa4caee37781
|
||||||
size 46271991
|
size 46271991
|
||||||
|
|||||||
@@ -84,12 +84,10 @@ Panda *connect(std::string serial="", uint32_t index=0) {
|
|||||||
panda->set_can_fd_auto(i, true);
|
panda->set_can_fd_auto(i, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_deprecated_panda = std::find(DEPRECATED_PANDA_TYPES.begin(),
|
bool is_supported_panda = std::find(SUPPORTED_PANDA_TYPES.begin(), SUPPORTED_PANDA_TYPES.end(), panda->hw_type) != SUPPORTED_PANDA_TYPES.end();
|
||||||
DEPRECATED_PANDA_TYPES.end(),
|
|
||||||
panda->hw_type) != DEPRECATED_PANDA_TYPES.end();
|
|
||||||
|
|
||||||
if (is_deprecated_panda) {
|
if (!is_supported_panda) {
|
||||||
LOGW("panda %s is deprecated (hw_type: %i), skipping firmware check...", panda->hw_serial().c_str(), static_cast<uint16_t>(panda->hw_type));
|
LOGW("panda %s is not supported (hw_type: %i), skipping firmware check...", panda->hw_serial().c_str(), static_cast<uint16_t>(panda->hw_type));
|
||||||
return panda.release();
|
return panda.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +173,6 @@ void fill_panda_state(cereal::PandaState::Builder &ps, cereal::PandaState::Panda
|
|||||||
ps.setHarnessStatus(cereal::PandaState::HarnessStatus(health.car_harness_status_pkt));
|
ps.setHarnessStatus(cereal::PandaState::HarnessStatus(health.car_harness_status_pkt));
|
||||||
ps.setInterruptLoad(health.interrupt_load_pkt);
|
ps.setInterruptLoad(health.interrupt_load_pkt);
|
||||||
ps.setFanPower(health.fan_power);
|
ps.setFanPower(health.fan_power);
|
||||||
ps.setFanStallCount(health.fan_stall_count);
|
|
||||||
ps.setSafetyRxChecksInvalid((bool)(health.safety_rx_checks_invalid_pkt));
|
ps.setSafetyRxChecksInvalid((bool)(health.safety_rx_checks_invalid_pkt));
|
||||||
ps.setSpiErrorCount(health.spi_error_count_pkt);
|
ps.setSpiErrorCount(health.spi_error_count_pkt);
|
||||||
ps.setSbu1Voltage(health.sbu1_voltage_mV / 1000.0f);
|
ps.setSbu1Voltage(health.sbu1_voltage_mV / 1000.0f);
|
||||||
|
|||||||
@@ -9,13 +9,10 @@
|
|||||||
void pandad_main_thread(std::vector<std::string> serials);
|
void pandad_main_thread(std::vector<std::string> serials);
|
||||||
|
|
||||||
// deprecated devices
|
// deprecated devices
|
||||||
static const std::vector<cereal::PandaState::PandaType> DEPRECATED_PANDA_TYPES = {
|
static const std::vector<cereal::PandaState::PandaType> SUPPORTED_PANDA_TYPES = {
|
||||||
cereal::PandaState::PandaType::WHITE_PANDA,
|
cereal::PandaState::PandaType::RED_PANDA,
|
||||||
cereal::PandaState::PandaType::GREY_PANDA,
|
cereal::PandaState::PandaType::TRES,
|
||||||
cereal::PandaState::PandaType::BLACK_PANDA,
|
cereal::PandaState::PandaType::CUATRO,
|
||||||
cereal::PandaState::PandaType::PEDAL,
|
|
||||||
cereal::PandaState::PandaType::UNO,
|
|
||||||
cereal::PandaState::PandaType::RED_PANDA_V2
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+20
-11
@@ -29,6 +29,12 @@ def flash_panda(panda_serial: str) -> Panda:
|
|||||||
HARDWARE.recover_internal_panda()
|
HARDWARE.recover_internal_panda()
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
# skip flashing if the detected panda is not supported
|
||||||
|
supported_panda = check_panda_support(panda)
|
||||||
|
if not supported_panda:
|
||||||
|
cloudlog.warning(f"Panda {panda_serial} is not supported (hw_type: {panda.get_type()}), skipping flash...")
|
||||||
|
return panda
|
||||||
|
|
||||||
fw_signature = get_expected_signature(panda)
|
fw_signature = get_expected_signature(panda)
|
||||||
internal_panda = panda.is_internal()
|
internal_panda = panda.is_internal()
|
||||||
|
|
||||||
@@ -36,12 +42,6 @@ def flash_panda(panda_serial: str) -> Panda:
|
|||||||
panda_signature = b"" if panda.bootstub else panda.get_signature()
|
panda_signature = b"" if panda.bootstub else panda.get_signature()
|
||||||
cloudlog.warning(f"Panda {panda_serial} connected, version: {panda_version}, signature {panda_signature.hex()[:16]}, expected {fw_signature.hex()[:16]}")
|
cloudlog.warning(f"Panda {panda_serial} connected, version: {panda_version}, signature {panda_signature.hex()[:16]}, expected {fw_signature.hex()[:16]}")
|
||||||
|
|
||||||
# skip flashing if the detected device is deprecated from upstream
|
|
||||||
hw_type = panda.get_type()
|
|
||||||
if hw_type in Panda.DEPRECATED_DEVICES:
|
|
||||||
cloudlog.warning(f"Panda {panda_serial} is deprecated (hw_type: {hw_type}), skipping flash...")
|
|
||||||
return panda
|
|
||||||
|
|
||||||
if panda.bootstub or panda_signature != fw_signature:
|
if panda.bootstub or panda_signature != fw_signature:
|
||||||
cloudlog.info("Panda firmware out of date, update required")
|
cloudlog.info("Panda firmware out of date, update required")
|
||||||
panda.flash()
|
panda.flash()
|
||||||
@@ -67,6 +67,14 @@ def flash_panda(panda_serial: str) -> Panda:
|
|||||||
return panda
|
return panda
|
||||||
|
|
||||||
|
|
||||||
|
def check_panda_support(panda) -> bool:
|
||||||
|
hw_type = panda.get_type()
|
||||||
|
if hw_type in Panda.SUPPORTED_DEVICES:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
# signal pandad to close the relay and exit
|
# signal pandad to close the relay and exit
|
||||||
def signal_handler(signum, frame):
|
def signal_handler(signum, frame):
|
||||||
@@ -91,11 +99,6 @@ def main() -> None:
|
|||||||
cloudlog.event("pandad.flash_and_connect", count=count)
|
cloudlog.event("pandad.flash_and_connect", count=count)
|
||||||
params.remove("PandaSignatures")
|
params.remove("PandaSignatures")
|
||||||
|
|
||||||
# TODO: remove this in the next AGNOS
|
|
||||||
# wait until USB is up before counting
|
|
||||||
if time.monotonic() < 60.:
|
|
||||||
no_internal_panda_count = 0
|
|
||||||
|
|
||||||
# Handle missing internal panda
|
# Handle missing internal panda
|
||||||
if no_internal_panda_count > 0:
|
if no_internal_panda_count > 0:
|
||||||
if no_internal_panda_count == 3:
|
if no_internal_panda_count == 3:
|
||||||
@@ -145,6 +148,12 @@ def main() -> None:
|
|||||||
params.put("PandaSignatures", b','.join(p.get_signature() for p in pandas))
|
params.put("PandaSignatures", b','.join(p.get_signature() for p in pandas))
|
||||||
|
|
||||||
for panda in pandas:
|
for panda in pandas:
|
||||||
|
# skip health check if the detected panda is not supported
|
||||||
|
supported_panda = check_panda_support(panda)
|
||||||
|
if not supported_panda:
|
||||||
|
cloudlog.warning(f"Panda {panda.get_usb_serial()} is not supported (hw_type: {panda.get_type()}), skipping health check...")
|
||||||
|
continue
|
||||||
|
|
||||||
# check health for lost heartbeat
|
# check health for lost heartbeat
|
||||||
health = panda.health()
|
health = panda.health()
|
||||||
if health["heartbeat_lost"]:
|
if health["heartbeat_lost"]:
|
||||||
|
|||||||
Binary file not shown.
@@ -22,8 +22,6 @@ class TestPandad:
|
|||||||
if len(Panda.list()) == 0:
|
if len(Panda.list()) == 0:
|
||||||
self._run_test(60)
|
self._run_test(60)
|
||||||
|
|
||||||
self.spi = HARDWARE.get_device_type() != 'tici'
|
|
||||||
|
|
||||||
def teardown_method(self):
|
def teardown_method(self):
|
||||||
managed_processes['pandad'].stop()
|
managed_processes['pandad'].stop()
|
||||||
|
|
||||||
@@ -106,11 +104,9 @@ class TestPandad:
|
|||||||
# - 0.2s pandad -> pandad
|
# - 0.2s pandad -> pandad
|
||||||
# - plus some buffer
|
# - plus some buffer
|
||||||
print("startup times", ts, sum(ts) / len(ts))
|
print("startup times", ts, sum(ts) / len(ts))
|
||||||
assert 0.1 < (sum(ts)/len(ts)) < (0.7 if self.spi else 5.0)
|
assert 0.1 < (sum(ts)/len(ts)) < 0.7
|
||||||
|
|
||||||
def test_protocol_version_check(self):
|
def test_protocol_version_check(self):
|
||||||
if not self.spi:
|
|
||||||
pytest.skip("SPI test")
|
|
||||||
# flash old fw
|
# flash old fw
|
||||||
fn = os.path.join(HERE, "bootstub.panda_h7_spiv0.bin")
|
fn = os.path.join(HERE, "bootstub.panda_h7_spiv0.bin")
|
||||||
self._flash_bootstub_and_test(fn, expect_mismatch=True)
|
self._flash_bootstub_and_test(fn, expect_mismatch=True)
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import random
|
|||||||
|
|
||||||
import cereal.messaging as messaging
|
import cereal.messaging as messaging
|
||||||
from cereal.services import SERVICE_LIST
|
from cereal.services import SERVICE_LIST
|
||||||
from openpilot.system.hardware import HARDWARE
|
|
||||||
from openpilot.selfdrive.test.helpers import with_processes
|
from openpilot.selfdrive.test.helpers import with_processes
|
||||||
from openpilot.selfdrive.pandad.tests.test_pandad_loopback import setup_pandad, send_random_can_messages
|
from openpilot.selfdrive.pandad.tests.test_pandad_loopback import setup_pandad, send_random_can_messages
|
||||||
|
|
||||||
@@ -16,8 +15,6 @@ JUNGLE_SPAM = "JUNGLE_SPAM" in os.environ
|
|||||||
class TestBoarddSpi:
|
class TestBoarddSpi:
|
||||||
@classmethod
|
@classmethod
|
||||||
def setup_class(cls):
|
def setup_class(cls):
|
||||||
if HARDWARE.get_device_type() == 'tici':
|
|
||||||
pytest.skip("only for spi pandas")
|
|
||||||
os.environ['STARTED'] = '1'
|
os.environ['STARTED'] = '1'
|
||||||
os.environ['SPI_ERR_PROB'] = '0.001'
|
os.environ['SPI_ERR_PROB'] = '0.001'
|
||||||
if not JUNGLE_SPAM:
|
if not JUNGLE_SPAM:
|
||||||
|
|||||||
@@ -29,10 +29,6 @@
|
|||||||
"text": "Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support.",
|
"text": "Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support.",
|
||||||
"severity": 1
|
"severity": 1
|
||||||
},
|
},
|
||||||
"Offroad_StorageMissing": {
|
|
||||||
"text": "NVMe drive not mounted.",
|
|
||||||
"severity": 1
|
|
||||||
},
|
|
||||||
"Offroad_CarUnrecognized": {
|
"Offroad_CarUnrecognized": {
|
||||||
"text": "sunnypilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai.",
|
"text": "sunnypilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai.",
|
||||||
"severity": 0
|
"severity": 0
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ def below_steer_speed_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.S
|
|||||||
f"Steer Unavailable Below {get_display_speed(CP.minSteerSpeed, metric)}",
|
f"Steer Unavailable Below {get_display_speed(CP.minSteerSpeed, metric)}",
|
||||||
"",
|
"",
|
||||||
AlertStatus.userPrompt, AlertSize.small,
|
AlertStatus.userPrompt, AlertSize.small,
|
||||||
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.prompt, 0.4)
|
Priority.LOW, VisualAlert.none, AudibleAlert.prompt, 0.4)
|
||||||
|
|
||||||
|
|
||||||
def calibration_incomplete_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
|
def calibration_incomplete_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
|
||||||
|
|||||||
@@ -21,12 +21,12 @@ from openpilot.selfdrive.selfdrived.helpers import ExcessiveActuationCheck
|
|||||||
from openpilot.selfdrive.selfdrived.state import StateMachine
|
from openpilot.selfdrive.selfdrived.state import StateMachine
|
||||||
from openpilot.selfdrive.selfdrived.alertmanager import AlertManager, set_offroad_alert
|
from openpilot.selfdrive.selfdrived.alertmanager import AlertManager, set_offroad_alert
|
||||||
|
|
||||||
from openpilot.system.hardware import HARDWARE
|
|
||||||
from openpilot.system.version import get_build_metadata
|
from openpilot.system.version import get_build_metadata
|
||||||
|
|
||||||
from openpilot.sunnypilot.mads.mads import ModularAssistiveDrivingSystem
|
from openpilot.sunnypilot.mads.mads import ModularAssistiveDrivingSystem
|
||||||
from openpilot.sunnypilot.selfdrive.car.car_specific import CarSpecificEventsSP
|
from openpilot.sunnypilot.selfdrive.car.car_specific import CarSpecificEventsSP
|
||||||
from openpilot.sunnypilot.selfdrive.car.cruise_helpers import CruiseHelper
|
from openpilot.sunnypilot.selfdrive.car.cruise_helpers import CruiseHelper
|
||||||
|
from openpilot.sunnypilot.selfdrive.car.intelligent_cruise_button_management.controller import IntelligentCruiseButtonManagement
|
||||||
from openpilot.sunnypilot.selfdrive.selfdrived.events import EventsSP
|
from openpilot.sunnypilot.selfdrive.selfdrived.events import EventsSP
|
||||||
|
|
||||||
REPLAY = "REPLAY" in os.environ
|
REPLAY = "REPLAY" in os.environ
|
||||||
@@ -96,7 +96,7 @@ class SelfdriveD(CruiseHelper):
|
|||||||
'carOutput', 'driverMonitoringState', 'longitudinalPlan', 'livePose', 'liveDelay',
|
'carOutput', 'driverMonitoringState', 'longitudinalPlan', 'livePose', 'liveDelay',
|
||||||
'managerState', 'liveParameters', 'radarState', 'liveTorqueParameters',
|
'managerState', 'liveParameters', 'radarState', 'liveTorqueParameters',
|
||||||
'controlsState', 'carControl', 'driverAssistance', 'alertDebug', 'userBookmark', 'audioFeedback',
|
'controlsState', 'carControl', 'driverAssistance', 'alertDebug', 'userBookmark', 'audioFeedback',
|
||||||
'modelDataV2SP'] + \
|
'modelDataV2SP', 'longitudinalPlanSP'] + \
|
||||||
self.camera_packets + self.sensor_packets + self.gps_packets,
|
self.camera_packets + self.sensor_packets + self.gps_packets,
|
||||||
ignore_alive=ignore, ignore_avg_freq=ignore,
|
ignore_alive=ignore, ignore_avg_freq=ignore,
|
||||||
ignore_valid=ignore, frequency=int(1/DT_CTRL))
|
ignore_valid=ignore, frequency=int(1/DT_CTRL))
|
||||||
@@ -135,13 +135,7 @@ class SelfdriveD(CruiseHelper):
|
|||||||
self.state_machine = StateMachine()
|
self.state_machine = StateMachine()
|
||||||
self.rk = Ratekeeper(100, print_delay_threshold=None)
|
self.rk = Ratekeeper(100, print_delay_threshold=None)
|
||||||
|
|
||||||
# some comma three with NVMe experience NVMe dropouts mid-drive that
|
self.ignored_processes = {'mapd', }
|
||||||
# cause loggerd to crash on write, so ignore it only on that platform
|
|
||||||
self.ignored_processes = set()
|
|
||||||
nvme_expected = os.path.exists('/dev/nvme0n1') or (not os.path.isfile("/persist/comma/living-in-the-moment"))
|
|
||||||
if HARDWARE.get_device_type() == 'tici' and nvme_expected:
|
|
||||||
self.ignored_processes = {'loggerd', }
|
|
||||||
self.ignored_processes.update({'mapd'})
|
|
||||||
|
|
||||||
# Determine startup event
|
# Determine startup event
|
||||||
is_remote = build_metadata.openpilot.comma_remote or build_metadata.openpilot.sunnypilot_remote
|
is_remote = build_metadata.openpilot.comma_remote or build_metadata.openpilot.sunnypilot_remote
|
||||||
@@ -163,8 +157,9 @@ class SelfdriveD(CruiseHelper):
|
|||||||
self.events_sp_prev = []
|
self.events_sp_prev = []
|
||||||
|
|
||||||
self.mads = ModularAssistiveDrivingSystem(self)
|
self.mads = ModularAssistiveDrivingSystem(self)
|
||||||
|
self.icbm = IntelligentCruiseButtonManagement(self.CP, self.CP_SP)
|
||||||
|
|
||||||
self.car_events_sp = CarSpecificEventsSP(self.CP, self.params)
|
self.car_events_sp = CarSpecificEventsSP(self.CP, self.CP_SP)
|
||||||
|
|
||||||
CruiseHelper.__init__(self, self.CP)
|
CruiseHelper.__init__(self, self.CP)
|
||||||
|
|
||||||
@@ -210,6 +205,7 @@ class SelfdriveD(CruiseHelper):
|
|||||||
|
|
||||||
if not self.CP.notCar:
|
if not self.CP.notCar:
|
||||||
self.events.add_from_msg(self.sm['driverMonitoringState'].events)
|
self.events.add_from_msg(self.sm['driverMonitoringState'].events)
|
||||||
|
self.events_sp.add_from_msg(self.sm['longitudinalPlanSP'].events)
|
||||||
|
|
||||||
# Add car events, ignore if CAN isn't valid
|
# Add car events, ignore if CAN isn't valid
|
||||||
if CS.canValid:
|
if CS.canValid:
|
||||||
@@ -449,6 +445,8 @@ class SelfdriveD(CruiseHelper):
|
|||||||
self.events.add(EventName.personalityChanged)
|
self.events.add(EventName.personalityChanged)
|
||||||
self.experimental_mode_switched = False
|
self.experimental_mode_switched = False
|
||||||
|
|
||||||
|
self.icbm.run(CS, self.sm['carControl'], self.sm['longitudinalPlanSP'], self.is_metric)
|
||||||
|
|
||||||
def data_sample(self):
|
def data_sample(self):
|
||||||
_car_state = messaging.recv_one(self.car_state_sock)
|
_car_state = messaging.recv_one(self.car_state_sock)
|
||||||
CS = _car_state.carState if _car_state else self.CS_prev
|
CS = _car_state.carState if _car_state else self.CS_prev
|
||||||
@@ -553,6 +551,11 @@ class SelfdriveD(CruiseHelper):
|
|||||||
mads.active = self.mads.active
|
mads.active = self.mads.active
|
||||||
mads.available = self.mads.enabled_toggle
|
mads.available = self.mads.enabled_toggle
|
||||||
|
|
||||||
|
icbm = ss_sp.intelligentCruiseButtonManagement
|
||||||
|
icbm.state = self.icbm.state
|
||||||
|
icbm.sendButton = self.icbm.cruise_button
|
||||||
|
icbm.vTarget = self.icbm.v_target
|
||||||
|
|
||||||
self.pm.send('selfdriveStateSP', ss_sp_msg)
|
self.pm.send('selfdriveStateSP', ss_sp_msg)
|
||||||
|
|
||||||
# onroadEventsSP - logged every second or on change
|
# onroadEventsSP - logged every second or on change
|
||||||
|
|||||||
@@ -67,6 +67,9 @@ class Plant:
|
|||||||
lp = messaging.new_message('liveParameters')
|
lp = messaging.new_message('liveParameters')
|
||||||
car_control = messaging.new_message('carControl')
|
car_control = messaging.new_message('carControl')
|
||||||
model = messaging.new_message('modelV2')
|
model = messaging.new_message('modelV2')
|
||||||
|
car_state_sp = messaging.new_message('carStateSP')
|
||||||
|
live_map_data_sp = messaging.new_message('liveMapDataSP')
|
||||||
|
gps_data = messaging.new_message('gpsLocation')
|
||||||
a_lead = (v_lead - self.v_lead_prev)/self.ts
|
a_lead = (v_lead - self.v_lead_prev)/self.ts
|
||||||
self.v_lead_prev = v_lead
|
self.v_lead_prev = v_lead
|
||||||
|
|
||||||
@@ -133,7 +136,10 @@ class Plant:
|
|||||||
'controlsState': control.controlsState,
|
'controlsState': control.controlsState,
|
||||||
'selfdriveState': ss.selfdriveState,
|
'selfdriveState': ss.selfdriveState,
|
||||||
'liveParameters': lp.liveParameters,
|
'liveParameters': lp.liveParameters,
|
||||||
'modelV2': model.modelV2}
|
'modelV2': model.modelV2,
|
||||||
|
'carStateSP': car_state_sp.carStateSP,
|
||||||
|
'liveMapDataSP': live_map_data_sp.liveMapDataSP,
|
||||||
|
'gpsLocation': gps_data.gpsLocation}
|
||||||
self.planner.update(sm)
|
self.planner.update(sm)
|
||||||
self.acceleration = self.planner.output_a_target
|
self.acceleration = self.planner.output_a_target
|
||||||
self.speed = self.speed + self.acceleration * self.ts
|
self.speed = self.speed + self.acceleration * self.ts
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ MigrationFunc = Callable[[list[MessageWithIndex]], MigrationOps]
|
|||||||
# 3. product is the message type created by the migration function, and the function will be skipped if product type already exists in lr
|
# 3. product is the message type created by the migration function, and the function will be skipped if product type already exists in lr
|
||||||
# 4. it must return a list of operations to be applied to the logreader (replace, add, delete)
|
# 4. it must return a list of operations to be applied to the logreader (replace, add, delete)
|
||||||
# 5. all migration functions must be independent of each other
|
# 5. all migration functions must be independent of each other
|
||||||
def migrate_all(lr: LogIterable, manager_states: bool = False, panda_states: bool = False, camera_states: bool = False):
|
def migrate_all(lr: LogIterable, manager_states: bool = False, panda_states: bool = False, camera_states: bool = False,
|
||||||
|
live_location_kalman: bool = True):
|
||||||
migrations = [
|
migrations = [
|
||||||
migrate_sensorEvents,
|
migrate_sensorEvents,
|
||||||
migrate_carParams,
|
migrate_carParams,
|
||||||
@@ -37,7 +38,6 @@ def migrate_all(lr: LogIterable, manager_states: bool = False, panda_states: boo
|
|||||||
migrate_carOutput,
|
migrate_carOutput,
|
||||||
migrate_controlsState,
|
migrate_controlsState,
|
||||||
migrate_carState,
|
migrate_carState,
|
||||||
migrate_liveLocationKalman,
|
|
||||||
migrate_liveTracks,
|
migrate_liveTracks,
|
||||||
migrate_driverAssistance,
|
migrate_driverAssistance,
|
||||||
migrate_drivingModelData,
|
migrate_drivingModelData,
|
||||||
@@ -51,6 +51,8 @@ def migrate_all(lr: LogIterable, manager_states: bool = False, panda_states: boo
|
|||||||
migrations.extend([migrate_pandaStates, migrate_peripheralState])
|
migrations.extend([migrate_pandaStates, migrate_peripheralState])
|
||||||
if camera_states:
|
if camera_states:
|
||||||
migrations.append(migrate_cameraStates)
|
migrations.append(migrate_cameraStates)
|
||||||
|
if live_location_kalman:
|
||||||
|
migrations.append(migrate_liveLocationKalman)
|
||||||
|
|
||||||
return migrate(lr, migrations)
|
return migrate(lr, migrations)
|
||||||
|
|
||||||
|
|||||||
@@ -496,7 +496,7 @@ CONFIGS = [
|
|||||||
pubs=[
|
pubs=[
|
||||||
"cameraOdometry", "accelerometer", "gyroscope", "liveCalibration", "carState"
|
"cameraOdometry", "accelerometer", "gyroscope", "liveCalibration", "carState"
|
||||||
],
|
],
|
||||||
subs=["livePose"],
|
subs=["liveLocationKalman", "livePose"],
|
||||||
ignore=["logMonoTime"],
|
ignore=["logMonoTime"],
|
||||||
should_recv_callback=MessageBasedRcvCallback("cameraOdometry"),
|
should_recv_callback=MessageBasedRcvCallback("cameraOdometry"),
|
||||||
tolerance=NUMPY_TOLERANCE,
|
tolerance=NUMPY_TOLERANCE,
|
||||||
@@ -595,7 +595,7 @@ def get_custom_params_from_lr(lr: LogIterable, initial_state: str = "first") ->
|
|||||||
if len(live_calibration) > 0:
|
if len(live_calibration) > 0:
|
||||||
custom_params["CalibrationParams"] = live_calibration[msg_index].as_builder().to_bytes()
|
custom_params["CalibrationParams"] = live_calibration[msg_index].as_builder().to_bytes()
|
||||||
if len(live_parameters) > 0:
|
if len(live_parameters) > 0:
|
||||||
custom_params["LiveParameters"] = live_parameters[msg_index].as_builder().to_bytes()
|
custom_params["LiveParametersV2"] = live_parameters[msg_index].as_builder().to_bytes()
|
||||||
if len(live_torque_parameters) > 0:
|
if len(live_torque_parameters) > 0:
|
||||||
custom_params["LiveTorqueParameters"] = live_torque_parameters[msg_index].as_builder().to_bytes()
|
custom_params["LiveTorqueParameters"] = live_torque_parameters[msg_index].as_builder().to_bytes()
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
6d3219bca9f66a229b38a5382d301a92b0147edb
|
afcab1abb62b9d5678342956cced4712f44e909e
|
||||||
@@ -18,7 +18,6 @@ from openpilot.common.timeout import Timeout
|
|||||||
from openpilot.common.params import Params
|
from openpilot.common.params import Params
|
||||||
from openpilot.selfdrive.selfdrived.events import EVENTS, ET
|
from openpilot.selfdrive.selfdrived.events import EVENTS, ET
|
||||||
from openpilot.selfdrive.test.helpers import set_params_enabled, release_only
|
from openpilot.selfdrive.test.helpers import set_params_enabled, release_only
|
||||||
from openpilot.system.hardware import HARDWARE
|
|
||||||
from openpilot.system.hardware.hw import Paths
|
from openpilot.system.hardware.hw import Paths
|
||||||
from openpilot.tools.lib.logreader import LogReader
|
from openpilot.tools.lib.logreader import LogReader
|
||||||
from openpilot.tools.lib.log_time_series import msgs_to_time_series
|
from openpilot.tools.lib.log_time_series import msgs_to_time_series
|
||||||
@@ -33,7 +32,7 @@ CPU usage budget
|
|||||||
TEST_DURATION = 25
|
TEST_DURATION = 25
|
||||||
LOG_OFFSET = 8
|
LOG_OFFSET = 8
|
||||||
|
|
||||||
MAX_TOTAL_CPU = 280. # total for all 8 cores
|
MAX_TOTAL_CPU = 300. # total for all 8 cores
|
||||||
PROCS = {
|
PROCS = {
|
||||||
# Baseline CPU usage by process
|
# Baseline CPU usage by process
|
||||||
"selfdrive.controls.controlsd": 16.0,
|
"selfdrive.controls.controlsd": 16.0,
|
||||||
@@ -57,30 +56,20 @@ PROCS = {
|
|||||||
"selfdrive.ui.soundd": 3.0,
|
"selfdrive.ui.soundd": 3.0,
|
||||||
"selfdrive.ui.feedback.feedbackd": 1.0,
|
"selfdrive.ui.feedback.feedbackd": 1.0,
|
||||||
"selfdrive.monitoring.dmonitoringd": 4.0,
|
"selfdrive.monitoring.dmonitoringd": 4.0,
|
||||||
"./proclogd": 2.0,
|
"system.proclogd": 3.0,
|
||||||
"system.logmessaged": 1.0,
|
"system.logmessaged": 1.0,
|
||||||
"system.tombstoned": 0,
|
"system.tombstoned": 0,
|
||||||
"./logcatd": 1.0,
|
"system.journald": 1.0,
|
||||||
"system.micd": 5.0,
|
"system.micd": 5.0,
|
||||||
"system.timed": 0,
|
"system.timed": 0,
|
||||||
"selfdrive.pandad.pandad": 0,
|
"selfdrive.pandad.pandad": 0,
|
||||||
"system.statsd": 1.0,
|
"system.statsd": 1.0,
|
||||||
"system.loggerd.uploader": 15.0,
|
"system.loggerd.uploader": 15.0,
|
||||||
"system.loggerd.deleter": 1.0,
|
"system.loggerd.deleter": 1.0,
|
||||||
|
"./pandad": 19.0,
|
||||||
|
"system.qcomgpsd.qcomgpsd": 1.0,
|
||||||
}
|
}
|
||||||
|
|
||||||
PROCS.update({
|
|
||||||
"tici": {
|
|
||||||
"./pandad": 5.0,
|
|
||||||
"./ubloxd": 1.0,
|
|
||||||
"system.ubloxd.pigeond": 6.0,
|
|
||||||
},
|
|
||||||
"tizi": {
|
|
||||||
"./pandad": 19.0,
|
|
||||||
"system.qcomgpsd.qcomgpsd": 1.0,
|
|
||||||
}
|
|
||||||
}.get(HARDWARE.get_device_type(), {}))
|
|
||||||
|
|
||||||
TIMINGS = {
|
TIMINGS = {
|
||||||
# rtols: max/min, rsd
|
# rtols: max/min, rsd
|
||||||
"can": [2.5, 0.35],
|
"can": [2.5, 0.35],
|
||||||
|
|||||||
@@ -63,14 +63,20 @@ class MainLayout(Widget):
|
|||||||
# Don't hide sidebar from interactive timeout
|
# Don't hide sidebar from interactive timeout
|
||||||
if self._current_mode != MainState.ONROAD:
|
if self._current_mode != MainState.ONROAD:
|
||||||
self._sidebar.set_visible(False)
|
self._sidebar.set_visible(False)
|
||||||
self._current_mode = MainState.ONROAD
|
self._set_current_layout(MainState.ONROAD)
|
||||||
else:
|
else:
|
||||||
self._current_mode = MainState.HOME
|
self._set_current_layout(MainState.HOME)
|
||||||
self._sidebar.set_visible(True)
|
self._sidebar.set_visible(True)
|
||||||
|
|
||||||
|
def _set_current_layout(self, layout: MainState):
|
||||||
|
if layout != self._current_mode:
|
||||||
|
self._layouts[self._current_mode].hide_event()
|
||||||
|
self._current_mode = layout
|
||||||
|
self._layouts[self._current_mode].show_event()
|
||||||
|
|
||||||
def open_settings(self, panel_type: PanelType):
|
def open_settings(self, panel_type: PanelType):
|
||||||
self._layouts[MainState.SETTINGS].set_current_panel(panel_type)
|
self._layouts[MainState.SETTINGS].set_current_panel(panel_type)
|
||||||
self._current_mode = MainState.SETTINGS
|
self._set_current_layout(MainState.SETTINGS)
|
||||||
self._sidebar.set_visible(False)
|
self._sidebar.set_visible(False)
|
||||||
|
|
||||||
def _on_settings_clicked(self):
|
def _on_settings_clicked(self):
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
import pyray as rl
|
|
||||||
from openpilot.system.ui.lib.wifi_manager import WifiManagerWrapper
|
|
||||||
from openpilot.system.ui.widgets import Widget
|
|
||||||
from openpilot.system.ui.widgets.network import WifiManagerUI
|
|
||||||
|
|
||||||
|
|
||||||
class NetworkLayout(Widget):
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
self.wifi_manager = WifiManagerWrapper()
|
|
||||||
self.wifi_ui = WifiManagerUI(self.wifi_manager)
|
|
||||||
|
|
||||||
def _render(self, rect: rl.Rectangle):
|
|
||||||
self.wifi_ui.render(rect)
|
|
||||||
|
|
||||||
def shutdown(self):
|
|
||||||
self.wifi_manager.shutdown()
|
|
||||||
@@ -2,7 +2,7 @@ import pyray as rl
|
|||||||
import time
|
import time
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
from openpilot.common.api import Api, api_get
|
from openpilot.common.api import api_get
|
||||||
from openpilot.common.params import Params
|
from openpilot.common.params import Params
|
||||||
from openpilot.common.swaglog import cloudlog
|
from openpilot.common.swaglog import cloudlog
|
||||||
from openpilot.selfdrive.ui.ui_state import ui_state
|
from openpilot.selfdrive.ui.ui_state import ui_state
|
||||||
@@ -11,7 +11,7 @@ from openpilot.system.ui.lib.application import gui_app, FontWeight
|
|||||||
from openpilot.system.ui.lib.scroll_panel import GuiScrollPanel
|
from openpilot.system.ui.lib.scroll_panel import GuiScrollPanel
|
||||||
from openpilot.system.ui.lib.wrap_text import wrap_text
|
from openpilot.system.ui.lib.wrap_text import wrap_text
|
||||||
from openpilot.system.ui.widgets import Widget
|
from openpilot.system.ui.widgets import Widget
|
||||||
|
from openpilot.selfdrive.ui.lib.api_helpers import get_token
|
||||||
|
|
||||||
TITLE = "Firehose Mode"
|
TITLE = "Firehose Mode"
|
||||||
DESCRIPTION = (
|
DESCRIPTION = (
|
||||||
@@ -163,7 +163,7 @@ class FirehoseLayout(Widget):
|
|||||||
dongle_id = self.params.get("DongleId")
|
dongle_id = self.params.get("DongleId")
|
||||||
if not dongle_id or dongle_id == UNREGISTERED_DONGLE_ID:
|
if not dongle_id or dongle_id == UNREGISTERED_DONGLE_ID:
|
||||||
return
|
return
|
||||||
identity_token = Api(dongle_id).get_token()
|
identity_token = get_token(dongle_id)
|
||||||
response = api_get(f"v1/devices/{dongle_id}/firehose_stats", access_token=identity_token)
|
response = api_get(f"v1/devices/{dongle_id}/firehose_stats", access_token=identity_token)
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import pyray as rl
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
from openpilot.selfdrive.ui.layouts.network import NetworkLayout
|
|
||||||
from openpilot.selfdrive.ui.layouts.settings.developer import DeveloperLayout
|
from openpilot.selfdrive.ui.layouts.settings.developer import DeveloperLayout
|
||||||
from openpilot.selfdrive.ui.layouts.settings.device import DeviceLayout
|
from openpilot.selfdrive.ui.layouts.settings.device import DeviceLayout
|
||||||
from openpilot.selfdrive.ui.layouts.settings.firehose import FirehoseLayout
|
from openpilot.selfdrive.ui.layouts.settings.firehose import FirehoseLayout
|
||||||
@@ -10,7 +9,9 @@ from openpilot.selfdrive.ui.layouts.settings.software import SoftwareLayout
|
|||||||
from openpilot.selfdrive.ui.layouts.settings.toggles import TogglesLayout
|
from openpilot.selfdrive.ui.layouts.settings.toggles import TogglesLayout
|
||||||
from openpilot.system.ui.lib.application import gui_app, FontWeight, MousePos
|
from openpilot.system.ui.lib.application import gui_app, FontWeight, MousePos
|
||||||
from openpilot.system.ui.lib.text_measure import measure_text_cached
|
from openpilot.system.ui.lib.text_measure import measure_text_cached
|
||||||
|
from openpilot.system.ui.lib.wifi_manager import WifiManager
|
||||||
from openpilot.system.ui.widgets import Widget
|
from openpilot.system.ui.widgets import Widget
|
||||||
|
from openpilot.system.ui.widgets.network import WifiManagerUI
|
||||||
|
|
||||||
# Settings close button
|
# Settings close button
|
||||||
SETTINGS_CLOSE_TEXT = "×"
|
SETTINGS_CLOSE_TEXT = "×"
|
||||||
@@ -43,7 +44,7 @@ class PanelType(IntEnum):
|
|||||||
@dataclass
|
@dataclass
|
||||||
class PanelInfo:
|
class PanelInfo:
|
||||||
name: str
|
name: str
|
||||||
instance: object
|
instance: Widget
|
||||||
button_rect: rl.Rectangle = rl.Rectangle(0, 0, 0, 0)
|
button_rect: rl.Rectangle = rl.Rectangle(0, 0, 0, 0)
|
||||||
|
|
||||||
|
|
||||||
@@ -53,9 +54,12 @@ class SettingsLayout(Widget):
|
|||||||
self._current_panel = PanelType.DEVICE
|
self._current_panel = PanelType.DEVICE
|
||||||
|
|
||||||
# Panel configuration
|
# Panel configuration
|
||||||
|
wifi_manager = WifiManager()
|
||||||
|
wifi_manager.set_active(False)
|
||||||
|
|
||||||
self._panels = {
|
self._panels = {
|
||||||
PanelType.DEVICE: PanelInfo("Device", DeviceLayout()),
|
PanelType.DEVICE: PanelInfo("Device", DeviceLayout()),
|
||||||
PanelType.NETWORK: PanelInfo("Network", NetworkLayout()),
|
PanelType.NETWORK: PanelInfo("Network", WifiManagerUI(wifi_manager)),
|
||||||
PanelType.TOGGLES: PanelInfo("Toggles", TogglesLayout()),
|
PanelType.TOGGLES: PanelInfo("Toggles", TogglesLayout()),
|
||||||
PanelType.SOFTWARE: PanelInfo("Software", SoftwareLayout()),
|
PanelType.SOFTWARE: PanelInfo("Software", SoftwareLayout()),
|
||||||
PanelType.FIREHOSE: PanelInfo("Firehose", FirehoseLayout()),
|
PanelType.FIREHOSE: PanelInfo("Firehose", FirehoseLayout()),
|
||||||
@@ -149,8 +153,14 @@ class SettingsLayout(Widget):
|
|||||||
|
|
||||||
def set_current_panel(self, panel_type: PanelType):
|
def set_current_panel(self, panel_type: PanelType):
|
||||||
if panel_type != self._current_panel:
|
if panel_type != self._current_panel:
|
||||||
|
self._panels[self._current_panel].instance.hide_event()
|
||||||
self._current_panel = panel_type
|
self._current_panel = panel_type
|
||||||
|
self._panels[self._current_panel].instance.show_event()
|
||||||
|
|
||||||
def close_settings(self):
|
def show_event(self):
|
||||||
if self._close_callback:
|
super().show_event()
|
||||||
self._close_callback()
|
self._panels[self._current_panel].instance.show_event()
|
||||||
|
|
||||||
|
def hide_event(self):
|
||||||
|
super().hide_event()
|
||||||
|
self._panels[self._current_panel].instance.hide_event()
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import time
|
||||||
|
from functools import lru_cache
|
||||||
|
from openpilot.common.api import Api
|
||||||
|
|
||||||
|
TOKEN_EXPIRY_HOURS = 2
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache(maxsize=1)
|
||||||
|
def _get_token(dongle_id: str, t: int):
|
||||||
|
return Api(dongle_id).get_token(expiry_hours=TOKEN_EXPIRY_HOURS)
|
||||||
|
|
||||||
|
|
||||||
|
def get_token(dongle_id: str):
|
||||||
|
return _get_token(dongle_id, int(time.monotonic() / (TOKEN_EXPIRY_HOURS / 2 * 60 * 60)))
|
||||||
@@ -2,14 +2,12 @@ from enum import IntEnum
|
|||||||
import os
|
import os
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
from functools import lru_cache
|
|
||||||
|
|
||||||
from openpilot.common.api import Api, api_get
|
from openpilot.common.api import api_get
|
||||||
from openpilot.common.params import Params
|
from openpilot.common.params import Params
|
||||||
from openpilot.common.swaglog import cloudlog
|
from openpilot.common.swaglog import cloudlog
|
||||||
from openpilot.system.athena.registration import UNREGISTERED_DONGLE_ID
|
from openpilot.system.athena.registration import UNREGISTERED_DONGLE_ID
|
||||||
|
from openpilot.selfdrive.ui.lib.api_helpers import get_token
|
||||||
TOKEN_EXPIRY_HOURS = 2
|
|
||||||
|
|
||||||
|
|
||||||
class PrimeType(IntEnum):
|
class PrimeType(IntEnum):
|
||||||
@@ -23,12 +21,6 @@ class PrimeType(IntEnum):
|
|||||||
PURPLE = 5,
|
PURPLE = 5,
|
||||||
|
|
||||||
|
|
||||||
@lru_cache(maxsize=1)
|
|
||||||
def get_token(dongle_id: str, t: int):
|
|
||||||
print('getting token')
|
|
||||||
return Api(dongle_id).get_token(expiry_hours=TOKEN_EXPIRY_HOURS)
|
|
||||||
|
|
||||||
|
|
||||||
class PrimeState:
|
class PrimeState:
|
||||||
FETCH_INTERVAL = 5.0 # seconds between API calls
|
FETCH_INTERVAL = 5.0 # seconds between API calls
|
||||||
API_TIMEOUT = 10.0 # seconds for API requests
|
API_TIMEOUT = 10.0 # seconds for API requests
|
||||||
@@ -58,15 +50,13 @@ class PrimeState:
|
|||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
identity_token = get_token(dongle_id, int(time.monotonic() / (TOKEN_EXPIRY_HOURS / 2 * 60 * 60)))
|
identity_token = get_token(dongle_id)
|
||||||
response = api_get(f"v1.1/devices/{dongle_id}", timeout=self.API_TIMEOUT, access_token=identity_token)
|
response = api_get(f"v1.1/devices/{dongle_id}", timeout=self.API_TIMEOUT, access_token=identity_token)
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
data = response.json()
|
data = response.json()
|
||||||
is_paired = data.get("is_paired", False)
|
is_paired = data.get("is_paired", False)
|
||||||
prime_type = data.get("prime_type", 0)
|
prime_type = data.get("prime_type", 0)
|
||||||
self.set_type(PrimeType(prime_type) if is_paired else PrimeType.UNPAIRED)
|
self.set_type(PrimeType(prime_type) if is_paired else PrimeType.UNPAIRED)
|
||||||
elif response.status_code == 401:
|
|
||||||
get_token.cache_clear()
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
cloudlog.error(f"Failed to fetch prime status: {e}")
|
cloudlog.error(f"Failed to fetch prime status: {e}")
|
||||||
|
|
||||||
|
|||||||
@@ -47,10 +47,11 @@ void HudRenderer::draw(QPainter &p, const QRect &surface_rect) {
|
|||||||
bg.setColorAt(1, QColor::fromRgbF(0, 0, 0, 0));
|
bg.setColorAt(1, QColor::fromRgbF(0, 0, 0, 0));
|
||||||
p.fillRect(0, 0, surface_rect.width(), UI_HEADER_HEIGHT, bg);
|
p.fillRect(0, 0, surface_rect.width(), UI_HEADER_HEIGHT, bg);
|
||||||
|
|
||||||
|
#ifndef SUNNYPILOT
|
||||||
if (is_cruise_available) {
|
if (is_cruise_available) {
|
||||||
drawSetSpeed(p, surface_rect);
|
drawSetSpeed(p, surface_rect);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
drawCurrentSpeed(p, surface_rect);
|
drawCurrentSpeed(p, surface_rect);
|
||||||
|
|
||||||
p.restore();
|
p.restore();
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ qt_src = [
|
|||||||
"sunnypilot/qt/offroad/offroad_home.cc",
|
"sunnypilot/qt/offroad/offroad_home.cc",
|
||||||
"sunnypilot/qt/offroad/settings/developer_panel.cc",
|
"sunnypilot/qt/offroad/settings/developer_panel.cc",
|
||||||
"sunnypilot/qt/offroad/settings/device_panel.cc",
|
"sunnypilot/qt/offroad/settings/device_panel.cc",
|
||||||
|
"sunnypilot/qt/offroad/settings/display_panel.cc",
|
||||||
"sunnypilot/qt/offroad/settings/lateral_panel.cc",
|
"sunnypilot/qt/offroad/settings/lateral_panel.cc",
|
||||||
"sunnypilot/qt/offroad/settings/longitudinal_panel.cc",
|
"sunnypilot/qt/offroad/settings/longitudinal_panel.cc",
|
||||||
"sunnypilot/qt/offroad/settings/max_time_offroad.cc",
|
"sunnypilot/qt/offroad/settings/max_time_offroad.cc",
|
||||||
@@ -50,10 +51,14 @@ lateral_panel_qt_src = [
|
|||||||
"sunnypilot/qt/offroad/settings/lateral/lane_change_settings.cc",
|
"sunnypilot/qt/offroad/settings/lateral/lane_change_settings.cc",
|
||||||
"sunnypilot/qt/offroad/settings/lateral/mads_settings.cc",
|
"sunnypilot/qt/offroad/settings/lateral/mads_settings.cc",
|
||||||
"sunnypilot/qt/offroad/settings/lateral/neural_network_lateral_control.cc",
|
"sunnypilot/qt/offroad/settings/lateral/neural_network_lateral_control.cc",
|
||||||
|
"sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_custom_params.cc",
|
||||||
|
"sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_settings.cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
longitudinal_panel_qt_src = [
|
longitudinal_panel_qt_src = [
|
||||||
"sunnypilot/qt/offroad/settings/longitudinal/custom_acc_increment.cc",
|
"sunnypilot/qt/offroad/settings/longitudinal/custom_acc_increment.cc",
|
||||||
|
"sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_policy.cc",
|
||||||
|
"sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_settings.cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
network_src = [
|
network_src = [
|
||||||
@@ -88,9 +93,13 @@ brand_settings_qt_src = [
|
|||||||
"sunnypilot/qt/offroad/settings/vehicle/volkswagen_settings.cc",
|
"sunnypilot/qt/offroad/settings/vehicle/volkswagen_settings.cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
display_panel_qt_src = [
|
||||||
|
"sunnypilot/qt/offroad/settings/display/onroad_screen_brightness.cc",
|
||||||
|
]
|
||||||
|
|
||||||
sp_widgets_src = widgets_src + network_src
|
sp_widgets_src = widgets_src + network_src
|
||||||
sp_qt_src = qt_src + lateral_panel_qt_src + vehicle_panel_qt_src + brand_settings_qt_src + longitudinal_panel_qt_src + osm_panel_qt_src
|
sp_qt_src = qt_src + lateral_panel_qt_src + vehicle_panel_qt_src + brand_settings_qt_src + \
|
||||||
|
longitudinal_panel_qt_src + osm_panel_qt_src + display_panel_qt_src
|
||||||
sp_qt_util = qt_util
|
sp_qt_util = qt_util
|
||||||
|
|
||||||
Export('sp_widgets_src', 'sp_qt_src', "sp_qt_util")
|
Export('sp_widgets_src', 'sp_qt_src', "sp_qt_util")
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/display/onroad_screen_brightness.h"
|
||||||
|
|
||||||
|
OnroadScreenBrightnessControl::OnroadScreenBrightnessControl(const QString ¶m, const QString &title,
|
||||||
|
const QString &description, const QString &icon,
|
||||||
|
QWidget *parent)
|
||||||
|
: ExpandableToggleRow(param, title, description, icon, parent) {
|
||||||
|
auto *mainFrame = new QFrame(this);
|
||||||
|
auto *mainFrameLayout = new QGridLayout();
|
||||||
|
mainFrame->setLayout(mainFrameLayout);
|
||||||
|
mainFrameLayout->setSpacing(0);
|
||||||
|
|
||||||
|
onroadScreenOffTimer = new OptionControlSP(
|
||||||
|
"OnroadScreenOffTimer",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
{0, 11}, 1, true, &onroadScreenOffTimerOptions);
|
||||||
|
|
||||||
|
onroadScreenBrightness = new OptionControlSP(
|
||||||
|
"OnroadScreenOffBrightness",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
{0, 100}, 10, true, nullptr, false);
|
||||||
|
|
||||||
|
connect(onroadScreenOffTimer, &OptionControlSP::updateLabels, this, &OnroadScreenBrightnessControl::refresh);
|
||||||
|
connect(onroadScreenBrightness, &OptionControlSP::updateLabels, this, &OnroadScreenBrightnessControl::refresh);
|
||||||
|
onroadScreenOffTimer->setFixedWidth(280);
|
||||||
|
onroadScreenBrightness->setFixedWidth(280);
|
||||||
|
mainFrameLayout->addWidget(onroadScreenOffTimer, 0, 0, Qt::AlignLeft);
|
||||||
|
mainFrameLayout->addWidget(onroadScreenBrightness, 0, 1, Qt::AlignRight);
|
||||||
|
|
||||||
|
addItem(mainFrame);
|
||||||
|
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnroadScreenBrightnessControl::refresh() {
|
||||||
|
// Driving Screen Off Timer
|
||||||
|
int valTimer = std::atoi(params.get("OnroadScreenOffTimer").c_str());
|
||||||
|
std::string labelTimer = "<span style='font-size: 45px; font-weight: 450; color: #FFFFFF;'>";
|
||||||
|
labelTimer += "Delay";
|
||||||
|
labelTimer += " <br><span style='font-size: 40px; font-weight: 450; color:rgb(174, 255, 195);'>";
|
||||||
|
labelTimer += (valTimer < 60 ? std::to_string(valTimer) + "s" : std::to_string(valTimer / 60) + "m");
|
||||||
|
labelTimer += "</span></span>";
|
||||||
|
onroadScreenOffTimer->setLabel(QString::fromStdString(labelTimer));
|
||||||
|
|
||||||
|
// Driving Screen Off Brightness
|
||||||
|
std::string valBrightness = params.get("OnroadScreenOffBrightness");
|
||||||
|
std::string labelBrightness = "<span style='font-size: 45px; font-weight: 450; color: #FFFFFF;'>";
|
||||||
|
labelBrightness += "Brightness";
|
||||||
|
labelBrightness += " <br><span style='font-size: 40px; font-weight: 450; color:rgb(174, 255, 195);'>";
|
||||||
|
labelBrightness += (valBrightness == "0" ? " Screen Off" : valBrightness + "%");
|
||||||
|
labelBrightness += "</span></span>";
|
||||||
|
onroadScreenBrightness->setLabel(QString::fromStdString(labelBrightness));
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||||
|
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h"
|
||||||
|
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
|
||||||
|
#include "selfdrive/ui/sunnypilot/qt/widgets/expandable_row.h"
|
||||||
|
|
||||||
|
static const QMap<QString, QString> onroadScreenOffTimerOptions = {
|
||||||
|
{"0", "15"},
|
||||||
|
{"1", "30"},
|
||||||
|
{"2", "60"},
|
||||||
|
{"3", "120"},
|
||||||
|
{"4", "180"},
|
||||||
|
{"5", "240"},
|
||||||
|
{"6", "300"},
|
||||||
|
{"7", "360"},
|
||||||
|
{"8", "420"},
|
||||||
|
{"9", "480"},
|
||||||
|
{"10", "540"},
|
||||||
|
{"11", "600"}
|
||||||
|
};
|
||||||
|
|
||||||
|
class OnroadScreenBrightnessControl : public ExpandableToggleRow {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
OnroadScreenBrightnessControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon,
|
||||||
|
QWidget *parent = nullptr);
|
||||||
|
void refresh();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Params params;
|
||||||
|
OptionControlSP *onroadScreenOffTimer;
|
||||||
|
OptionControlSP *onroadScreenBrightness;
|
||||||
|
};
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/display_panel.h"
|
||||||
|
|
||||||
|
DisplayPanel::DisplayPanel(QWidget *parent) : QWidget(parent) {
|
||||||
|
main_layout = new QStackedLayout(this);
|
||||||
|
ListWidgetSP *list = new ListWidgetSP(this, false);
|
||||||
|
|
||||||
|
sunnypilotScreen = new QWidget(this);
|
||||||
|
QVBoxLayout* vlayout = new QVBoxLayout(sunnypilotScreen);
|
||||||
|
vlayout->setContentsMargins(50, 20, 50, 20);
|
||||||
|
|
||||||
|
// Onroad Screen Off/Brightness
|
||||||
|
onroadScreenBrightnessControl = new OnroadScreenBrightnessControl(
|
||||||
|
"OnroadScreenOffControl",
|
||||||
|
tr("Driving Screen Off: Non-Critical Events"),
|
||||||
|
tr("Turn off device screen or reduce brightness after driving starts. "
|
||||||
|
"It automatically brightens again when screen is touched or a critical event occurs."),
|
||||||
|
"",
|
||||||
|
this);
|
||||||
|
list->addItem(onroadScreenBrightnessControl);
|
||||||
|
|
||||||
|
sunnypilotScroller = new ScrollViewSP(list, this);
|
||||||
|
vlayout->addWidget(sunnypilotScroller);
|
||||||
|
main_layout->addWidget(sunnypilotScreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisplayPanel::showEvent(QShowEvent *event) {
|
||||||
|
QWidget::showEvent(event);
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisplayPanel::refresh() {
|
||||||
|
onroadScreenBrightnessControl->refresh();
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/display/onroad_screen_brightness.h"
|
||||||
|
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h"
|
||||||
|
#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h"
|
||||||
|
|
||||||
|
class DisplayPanel : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DisplayPanel(QWidget *parent = nullptr);
|
||||||
|
void showEvent(QShowEvent *event) override;
|
||||||
|
void refresh();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QStackedLayout* main_layout = nullptr;
|
||||||
|
QWidget* sunnypilotScreen = nullptr;
|
||||||
|
ScrollViewSP *sunnypilotScroller = nullptr;
|
||||||
|
Params params;
|
||||||
|
OnroadScreenBrightnessControl *onroadScreenBrightnessControl = nullptr;
|
||||||
|
};
|
||||||
@@ -52,12 +52,16 @@ void MadsSettings::updateToggles(bool _offroad) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
auto cp_bytes = params.get("CarParamsPersistent");
|
auto cp_bytes = params.get("CarParamsPersistent");
|
||||||
if (!cp_bytes.empty()) {
|
auto cp_sp_bytes = params.get("CarParamsSPPersistent");
|
||||||
|
if (!cp_bytes.empty() && !cp_sp_bytes.empty()) {
|
||||||
AlignedBuffer aligned_buf;
|
AlignedBuffer aligned_buf;
|
||||||
|
AlignedBuffer aligned_buf_sp;
|
||||||
capnp::FlatArrayMessageReader cmsg(aligned_buf.align(cp_bytes.data(), cp_bytes.size()));
|
capnp::FlatArrayMessageReader cmsg(aligned_buf.align(cp_bytes.data(), cp_bytes.size()));
|
||||||
|
capnp::FlatArrayMessageReader cmsg_sp(aligned_buf_sp.align(cp_sp_bytes.data(), cp_sp_bytes.size()));
|
||||||
cereal::CarParams::Reader CP = cmsg.getRoot<cereal::CarParams>();
|
cereal::CarParams::Reader CP = cmsg.getRoot<cereal::CarParams>();
|
||||||
|
cereal::CarParamsSP::Reader CP_SP = cmsg_sp.getRoot<cereal::CarParamsSP>();
|
||||||
|
|
||||||
if (isBrandInList(CP.getBrand(), mads_limited_settings_brands)) {
|
if (madsLimitedSettings(CP, CP_SP)) {
|
||||||
params.remove("MadsMainCruiseAllowed");
|
params.remove("MadsMainCruiseAllowed");
|
||||||
params.putBool("MadsUnifiedEngagementMode", true);
|
params.putBool("MadsUnifiedEngagementMode", true);
|
||||||
params.put("MadsSteeringMode", std::to_string(static_cast<int>(MadsSteeringMode::DISENGAGE)));
|
params.put("MadsSteeringMode", std::to_string(static_cast<int>(MadsSteeringMode::DISENGAGE)));
|
||||||
|
|||||||
@@ -12,7 +12,16 @@
|
|||||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h"
|
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h"
|
||||||
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
|
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
|
||||||
|
|
||||||
const std::vector<std::string> mads_limited_settings_brands = {"rivian", "tesla"};
|
inline bool madsLimitedSettings(const cereal::CarParams::Reader &CP, const cereal::CarParamsSP::Reader &CP_SP) {
|
||||||
|
if (CP.getBrand() == "rivian") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (CP.getBrand() == "tesla") {
|
||||||
|
return !(CP_SP.getFlags() & 1); // 1 == TeslaFlagsSP.HAS_VEHICLE_BUS
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
enum class MadsSteeringMode {
|
enum class MadsSteeringMode {
|
||||||
REMAIN_ACTIVE = 0,
|
REMAIN_ACTIVE = 0,
|
||||||
|
|||||||
+11
-3
@@ -10,14 +10,15 @@
|
|||||||
NeuralNetworkLateralControl::NeuralNetworkLateralControl() :
|
NeuralNetworkLateralControl::NeuralNetworkLateralControl() :
|
||||||
ParamControl("NeuralNetworkLateralControl", tr("Neural Network Lateral Control (NNLC)"), "", "") {
|
ParamControl("NeuralNetworkLateralControl", tr("Neural Network Lateral Control (NNLC)"), "", "") {
|
||||||
setConfirmation(true, false);
|
setConfirmation(true, false);
|
||||||
updateToggle();
|
updateToggle(offroad);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NeuralNetworkLateralControl::updateToggle() {
|
void NeuralNetworkLateralControl::updateToggle(bool _offroad) {
|
||||||
QString statusInitText = "<font color='yellow'>" + STATUS_CHECK_COMPATIBILITY + "</font>";
|
QString statusInitText = "<font color='yellow'>" + STATUS_CHECK_COMPATIBILITY + "</font>";
|
||||||
QString notLoadedText = "<font color='yellow'>" + STATUS_NOT_LOADED + "</font>";
|
QString notLoadedText = "<font color='yellow'>" + STATUS_NOT_LOADED + "</font>";
|
||||||
QString loadedText = "<font color=#00ff00>" + STATUS_LOADED + "</font>";
|
QString loadedText = "<font color=#00ff00>" + STATUS_LOADED + "</font>";
|
||||||
|
|
||||||
|
bool allowed = true;
|
||||||
auto cp_bytes = params.get("CarParamsPersistent");
|
auto cp_bytes = params.get("CarParamsPersistent");
|
||||||
auto cp_sp_bytes = params.get("CarParamsSPPersistent");
|
auto cp_sp_bytes = params.get("CarParamsSPPersistent");
|
||||||
if (!cp_bytes.empty() && !cp_sp_bytes.empty()) {
|
if (!cp_bytes.empty() && !cp_sp_bytes.empty()) {
|
||||||
@@ -31,7 +32,7 @@ void NeuralNetworkLateralControl::updateToggle() {
|
|||||||
if (CP.getSteerControlType() == cereal::CarParams::SteerControlType::ANGLE) {
|
if (CP.getSteerControlType() == cereal::CarParams::SteerControlType::ANGLE) {
|
||||||
params.remove("NeuralNetworkLateralControl");
|
params.remove("NeuralNetworkLateralControl");
|
||||||
setDescription(nnffDescriptionBuilder(STATUS_NOT_AVAILABLE));
|
setDescription(nnffDescriptionBuilder(STATUS_NOT_AVAILABLE));
|
||||||
setEnabled(false);
|
allowed = false;
|
||||||
} else {
|
} else {
|
||||||
QString nn_model_name = QString::fromStdString(CP_SP.getNeuralNetworkLateralControl().getModel().getName());
|
QString nn_model_name = QString::fromStdString(CP_SP.getNeuralNetworkLateralControl().getModel().getName());
|
||||||
QString nn_fuzzy = CP_SP.getNeuralNetworkLateralControl().getFuzzyFingerprint() ?
|
QString nn_fuzzy = CP_SP.getNeuralNetworkLateralControl().getFuzzyFingerprint() ?
|
||||||
@@ -56,4 +57,11 @@ void NeuralNetworkLateralControl::updateToggle() {
|
|||||||
if (getDescription() != getBaseDescription()) {
|
if (getDescription() != getBaseDescription()) {
|
||||||
showDescription();
|
showDescription();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool enforce_torque_toggle = params.getBool("EnforceTorqueControl");
|
||||||
|
setEnabled(_offroad && allowed && !enforce_torque_toggle);
|
||||||
|
|
||||||
|
refresh();
|
||||||
|
|
||||||
|
offroad = _offroad;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -20,10 +20,11 @@ public:
|
|||||||
NeuralNetworkLateralControl();
|
NeuralNetworkLateralControl();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void updateToggle();
|
void updateToggle(bool _offroad);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Params params;
|
Params params;
|
||||||
|
bool offroad;
|
||||||
|
|
||||||
// Status messages
|
// Status messages
|
||||||
const QString STATUS_NOT_AVAILABLE = tr("NNLC is currently not available on this platform.");
|
const QString STATUS_NOT_AVAILABLE = tr("NNLC is currently not available on this platform.");
|
||||||
|
|||||||
+58
@@ -0,0 +1,58 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_custom_params.h"
|
||||||
|
|
||||||
|
TorqueLateralControlCustomParams::TorqueLateralControlCustomParams(const QString ¶m, const QString &title, const QString &description, const QString &icon, QWidget *parent)
|
||||||
|
: ExpandableToggleRow(param, title, description, icon, parent) {
|
||||||
|
|
||||||
|
QFrame *frame = new QFrame(this);
|
||||||
|
QGridLayout *frame_layout = new QGridLayout();
|
||||||
|
frame->setLayout(frame_layout);
|
||||||
|
frame_layout->setSpacing(0);
|
||||||
|
|
||||||
|
torqueLateralControlParamsOverride = new ParamControl(
|
||||||
|
"TorqueParamsOverrideEnabled",
|
||||||
|
tr("Manual Real-Time Tuning"),
|
||||||
|
tr("Enforces the torque lateral controller to use the fixed values instead of the learned values from Self-Tune. Enabling this toggle overrides Self-Tune values."),
|
||||||
|
"../assets/offroad/icon_blank.png",
|
||||||
|
this
|
||||||
|
);
|
||||||
|
connect(torqueLateralControlParamsOverride, &ParamControl::toggleFlipped, this, &TorqueLateralControlCustomParams::refresh);
|
||||||
|
|
||||||
|
torqueParamsOverrideLatAccelFactor = new OptionControlSP("TorqueParamsOverrideLatAccelFactor", tr("Lateral Acceleration Factor"), "", "", {1, 500}, 1, false, nullptr, true, false);
|
||||||
|
connect(torqueParamsOverrideLatAccelFactor, &OptionControlSP::updateLabels, this, &TorqueLateralControlCustomParams::refresh);
|
||||||
|
torqueParamsOverrideLatAccelFactor->setFixedWidth(280);
|
||||||
|
|
||||||
|
torqueParamsOverrideFriction = new OptionControlSP("TorqueParamsOverrideFriction", tr("Friction"), "", "", {1, 100}, 1, false, nullptr, true, false);
|
||||||
|
connect(torqueParamsOverrideFriction, &OptionControlSP::updateLabels, this, &TorqueLateralControlCustomParams::refresh);
|
||||||
|
torqueParamsOverrideFriction->setFixedWidth(280);
|
||||||
|
|
||||||
|
frame_layout->addWidget(torqueLateralControlParamsOverride, 0, 0, 1, 2);
|
||||||
|
QSpacerItem *spacer = new QSpacerItem(20, 40);
|
||||||
|
frame_layout->addItem(spacer, 1, 0, 1, 2);
|
||||||
|
frame_layout->addWidget(torqueParamsOverrideLatAccelFactor, 2, 0, Qt::AlignCenter);
|
||||||
|
frame_layout->addWidget(torqueParamsOverrideFriction, 2, 1, Qt::AlignCenter);
|
||||||
|
|
||||||
|
addItem(frame);
|
||||||
|
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TorqueLateralControlCustomParams::refresh() {
|
||||||
|
bool torque_override_param = params.getBool("TorqueParamsOverrideEnabled");
|
||||||
|
float laf_param = QString::fromStdString(params.get("TorqueParamsOverrideLatAccelFactor")).toFloat();
|
||||||
|
const QString laf_unit = "m/s²";
|
||||||
|
|
||||||
|
float friction_param = QString::fromStdString(params.get("TorqueParamsOverrideFriction")).toFloat();
|
||||||
|
|
||||||
|
torqueParamsOverrideLatAccelFactor->setTitle(tr("Lateral Acceleration Factor") + "\n(" + (torque_override_param ? tr("Real-time and Offline") : tr("Offline Only")) + ")");
|
||||||
|
torqueParamsOverrideFriction->setTitle(tr("Friction") + "\n(" + (torque_override_param ? tr("Real-time and Offline") : tr("Offline Only")) + ")");
|
||||||
|
|
||||||
|
torqueParamsOverrideLatAccelFactor->setLabel(QString::number(laf_param, 'f', 2) + " " + laf_unit);
|
||||||
|
torqueParamsOverrideFriction->setLabel(QString::number(friction_param, 'f', 2));
|
||||||
|
}
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||||
|
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h"
|
||||||
|
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
|
||||||
|
#include "selfdrive/ui/sunnypilot/qt/widgets/expandable_row.h"
|
||||||
|
|
||||||
|
class TorqueLateralControlCustomParams : public ExpandableToggleRow {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
TorqueLateralControlCustomParams(const QString ¶m, const QString &title, const QString &description, const QString &icon, QWidget *parent = nullptr);
|
||||||
|
void refresh();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Params params;
|
||||||
|
ParamControl *torqueLateralControlParamsOverride;
|
||||||
|
OptionControlSP *torqueParamsOverrideFriction;
|
||||||
|
OptionControlSP *torqueParamsOverrideLatAccelFactor;
|
||||||
|
};
|
||||||
+81
@@ -0,0 +1,81 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_settings.h"
|
||||||
|
|
||||||
|
#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h"
|
||||||
|
|
||||||
|
TorqueLateralControlSettings::TorqueLateralControlSettings(QWidget *parent) : QWidget(parent) {
|
||||||
|
QVBoxLayout *main_layout = new QVBoxLayout(this);
|
||||||
|
main_layout->setContentsMargins(50, 20, 50, 20);
|
||||||
|
main_layout->setSpacing(20);
|
||||||
|
|
||||||
|
// Back button
|
||||||
|
PanelBackButton *back = new PanelBackButton();
|
||||||
|
connect(back, &QPushButton::clicked, [=]() { emit backPress(); });
|
||||||
|
main_layout->addWidget(back, 0, Qt::AlignLeft);
|
||||||
|
|
||||||
|
ListWidget *list = new ListWidget(this, false);
|
||||||
|
// param, title, desc, icon
|
||||||
|
std::vector<std::tuple<QString, QString, QString, QString>> toggle_defs{
|
||||||
|
{
|
||||||
|
"LiveTorqueParamsToggle",
|
||||||
|
tr("Self-Tune"),
|
||||||
|
tr("Enables self-tune for Torque lateral control for platforms that do not use Torque lateral control by default."),
|
||||||
|
"../assets/offroad/icon_blank.png",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"LiveTorqueParamsRelaxedToggle",
|
||||||
|
tr("Less Restrict Settings for Self-Tune (Beta)"),
|
||||||
|
tr("Less strict settings when using Self-Tune. This allows torqued to be more forgiving when learning values."),
|
||||||
|
"../assets/offroad/icon_blank.png",
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto &[param, title, desc, icon] : toggle_defs) {
|
||||||
|
auto toggle = new ParamControlSP(param, title, desc, icon, this);
|
||||||
|
list->addItem(toggle);
|
||||||
|
toggles[param.toStdString()] = toggle;
|
||||||
|
}
|
||||||
|
|
||||||
|
torqueLateralControlCustomParams = new TorqueLateralControlCustomParams(
|
||||||
|
"CustomTorqueParams",
|
||||||
|
tr("Enable Custom Tuning"),
|
||||||
|
tr("Enables custom tuning for Torque lateral control. Modifying Lateral Acceleration Factor and Friction below will override the offline values indicated in the YAML files within \"opendbc/car/torque_data\". "
|
||||||
|
"The values will also be used live when \"Manual Real-Time Tuning\" toggle is enabled."),
|
||||||
|
"../assets/offroad/icon_blank.png",
|
||||||
|
this);
|
||||||
|
list->addItem(torqueLateralControlCustomParams);
|
||||||
|
|
||||||
|
QObject::connect(uiState(), &UIState::offroadTransition, this, &TorqueLateralControlSettings::updateToggles);
|
||||||
|
QObject::connect(toggles["LiveTorqueParamsToggle"], &ParamControlSP::toggleFlipped, [=](bool state) {
|
||||||
|
if (!state) {
|
||||||
|
params.remove("LiveTorqueParamsRelaxedToggle");
|
||||||
|
toggles["LiveTorqueParamsRelaxedToggle"]->refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateToggles(offroad);
|
||||||
|
});
|
||||||
|
|
||||||
|
main_layout->addWidget(new ScrollViewSP(list, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TorqueLateralControlSettings::showEvent(QShowEvent *event) {
|
||||||
|
updateToggles(offroad);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TorqueLateralControlSettings::updateToggles(bool _offroad) {
|
||||||
|
bool live_toggle = toggles["LiveTorqueParamsToggle"]->isToggled();
|
||||||
|
|
||||||
|
toggles["LiveTorqueParamsToggle"]->setEnabled(_offroad);
|
||||||
|
toggles["LiveTorqueParamsRelaxedToggle"]->setEnabled(_offroad && live_toggle);
|
||||||
|
|
||||||
|
torqueLateralControlCustomParams->setEnabled(_offroad);
|
||||||
|
torqueLateralControlCustomParams->refresh();
|
||||||
|
|
||||||
|
offroad = _offroad;
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "selfdrive/ui/qt/util.h"
|
||||||
|
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||||
|
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_custom_params.h"
|
||||||
|
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h"
|
||||||
|
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
|
||||||
|
|
||||||
|
class TorqueLateralControlSettings : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit TorqueLateralControlSettings(QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
void showEvent(QShowEvent *event) override;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void backPress();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void updateToggles(bool _offroad);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Params params;
|
||||||
|
bool offroad;
|
||||||
|
std::map<std::string, ParamControlSP*> toggles;
|
||||||
|
|
||||||
|
TorqueLateralControlCustomParams *torqueLateralControlCustomParams;
|
||||||
|
};
|
||||||
@@ -75,6 +75,36 @@ LateralPanel::LateralPanel(SettingsWindowSP *parent) : QFrame(parent) {
|
|||||||
|
|
||||||
list->addItem(horizontal_line());
|
list->addItem(horizontal_line());
|
||||||
|
|
||||||
|
// Customized Torque Lateral Control
|
||||||
|
torqueLateralControlToggle = new ParamControl(
|
||||||
|
"EnforceTorqueControl",
|
||||||
|
tr("Enforce Torque Lateral Control"),
|
||||||
|
tr("Enable this to enforce sunnypilot to steer with Torque lateral control."),
|
||||||
|
"");
|
||||||
|
list->addItem(torqueLateralControlToggle);
|
||||||
|
|
||||||
|
torqueLateralControlSettingsButton = new PushButtonSP(tr("Customize Params"));
|
||||||
|
torqueLateralControlSettingsButton->setObjectName("torque_btn");
|
||||||
|
connect(torqueLateralControlSettingsButton, &QPushButton::clicked, [=]() {
|
||||||
|
sunnypilotScroller->setLastScrollPosition();
|
||||||
|
main_layout->setCurrentWidget(torqueLateralControlWidget);
|
||||||
|
});
|
||||||
|
QObject::connect(torqueLateralControlToggle, &ToggleControl::toggleFlipped, [=](bool state) {
|
||||||
|
torqueLateralControlSettingsButton->setEnabled(state);
|
||||||
|
nnlcToggle->updateToggle(offroad);
|
||||||
|
updateToggles(offroad);
|
||||||
|
});
|
||||||
|
|
||||||
|
torqueLateralControlWidget = new TorqueLateralControlSettings(this);
|
||||||
|
connect(torqueLateralControlWidget, &TorqueLateralControlSettings::backPress, [=]() {
|
||||||
|
sunnypilotScroller->restoreScrollPosition();
|
||||||
|
main_layout->setCurrentWidget(sunnypilotScreen);
|
||||||
|
});
|
||||||
|
list->addItem(torqueLateralControlSettingsButton);
|
||||||
|
|
||||||
|
list->addItem(vertical_space(0));
|
||||||
|
list->addItem(horizontal_line());
|
||||||
|
|
||||||
// Neural Network Lateral Control
|
// Neural Network Lateral Control
|
||||||
nnlcToggle = new NeuralNetworkLateralControl();
|
nnlcToggle = new NeuralNetworkLateralControl();
|
||||||
list->addItem(nnlcToggle);
|
list->addItem(nnlcToggle);
|
||||||
@@ -86,12 +116,10 @@ LateralPanel::LateralPanel(SettingsWindowSP *parent) : QFrame(parent) {
|
|||||||
nnlcToggle->hideDescription();
|
nnlcToggle->hideDescription();
|
||||||
}
|
}
|
||||||
|
|
||||||
nnlcToggle->updateToggle();
|
nnlcToggle->updateToggle(offroad);
|
||||||
|
updateToggles(offroad);
|
||||||
});
|
});
|
||||||
|
|
||||||
toggleOffroadOnly = {
|
|
||||||
madsToggle, nnlcToggle,
|
|
||||||
};
|
|
||||||
QObject::connect(uiState(), &UIState::offroadTransition, this, &LateralPanel::updateToggles);
|
QObject::connect(uiState(), &UIState::offroadTransition, this, &LateralPanel::updateToggles);
|
||||||
|
|
||||||
sunnypilotScroller = new ScrollViewSP(list, this);
|
sunnypilotScroller = new ScrollViewSP(list, this);
|
||||||
@@ -100,6 +128,7 @@ LateralPanel::LateralPanel(SettingsWindowSP *parent) : QFrame(parent) {
|
|||||||
main_layout->addWidget(sunnypilotScreen);
|
main_layout->addWidget(sunnypilotScreen);
|
||||||
main_layout->addWidget(madsWidget);
|
main_layout->addWidget(madsWidget);
|
||||||
main_layout->addWidget(laneChangeWidget);
|
main_layout->addWidget(laneChangeWidget);
|
||||||
|
main_layout->addWidget(torqueLateralControlWidget);
|
||||||
|
|
||||||
setStyleSheet(R"(
|
setStyleSheet(R"(
|
||||||
#back_btn {
|
#back_btn {
|
||||||
@@ -120,7 +149,7 @@ LateralPanel::LateralPanel(SettingsWindowSP *parent) : QFrame(parent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void LateralPanel::showEvent(QShowEvent *event) {
|
void LateralPanel::showEvent(QShowEvent *event) {
|
||||||
nnlcToggle->updateToggle();
|
nnlcToggle->updateToggle(offroad);
|
||||||
updateToggles(offroad);
|
updateToggles(offroad);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,27 +158,40 @@ void LateralPanel::hideEvent(QHideEvent *event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void LateralPanel::updateToggles(bool _offroad) {
|
void LateralPanel::updateToggles(bool _offroad) {
|
||||||
for (auto *toggle : toggleOffroadOnly) {
|
bool torque_allowed = true;
|
||||||
toggle->setEnabled(_offroad);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto cp_bytes = params.get("CarParamsPersistent");
|
auto cp_bytes = params.get("CarParamsPersistent");
|
||||||
if (!cp_bytes.empty()) {
|
auto cp_sp_bytes = params.get("CarParamsSPPersistent");
|
||||||
|
if (!cp_bytes.empty() && !cp_sp_bytes.empty()) {
|
||||||
AlignedBuffer aligned_buf;
|
AlignedBuffer aligned_buf;
|
||||||
|
AlignedBuffer aligned_buf_sp;
|
||||||
capnp::FlatArrayMessageReader cmsg(aligned_buf.align(cp_bytes.data(), cp_bytes.size()));
|
capnp::FlatArrayMessageReader cmsg(aligned_buf.align(cp_bytes.data(), cp_bytes.size()));
|
||||||
|
capnp::FlatArrayMessageReader cmsg_sp(aligned_buf_sp.align(cp_sp_bytes.data(), cp_sp_bytes.size()));
|
||||||
cereal::CarParams::Reader CP = cmsg.getRoot<cereal::CarParams>();
|
cereal::CarParams::Reader CP = cmsg.getRoot<cereal::CarParams>();
|
||||||
|
cereal::CarParamsSP::Reader CP_SP = cmsg_sp.getRoot<cereal::CarParamsSP>();
|
||||||
|
|
||||||
if (isBrandInList(CP.getBrand(), mads_limited_settings_brands)) {
|
if (madsLimitedSettings(CP, CP_SP)) {
|
||||||
madsToggle->setDescription(descriptionBuilder(STATUS_MADS_SETTINGS_LIMITED_COMPATIBILITY, MADS_BASE_DESC));
|
madsToggle->setDescription(descriptionBuilder(STATUS_MADS_SETTINGS_LIMITED_COMPATIBILITY, MADS_BASE_DESC));
|
||||||
} else {
|
} else {
|
||||||
madsToggle->setDescription(descriptionBuilder(STATUS_MADS_SETTINGS_FULL_COMPATIBILITY, MADS_BASE_DESC));
|
madsToggle->setDescription(descriptionBuilder(STATUS_MADS_SETTINGS_FULL_COMPATIBILITY, MADS_BASE_DESC));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (CP.getSteerControlType() == cereal::CarParams::SteerControlType::ANGLE) {
|
||||||
|
params.remove("EnforceTorqueControl");
|
||||||
|
torque_allowed = false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
madsToggle->setDescription(descriptionBuilder(STATUS_MADS_CHECK_COMPATIBILITY, MADS_BASE_DESC));
|
madsToggle->setDescription(descriptionBuilder(STATUS_MADS_CHECK_COMPATIBILITY, MADS_BASE_DESC));
|
||||||
|
|
||||||
|
params.remove("EnforceTorqueControl");
|
||||||
|
torque_allowed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
madsToggle->setEnabled(_offroad);
|
||||||
madsSettingsButton->setEnabled(madsToggle->isToggled());
|
madsSettingsButton->setEnabled(madsToggle->isToggled());
|
||||||
|
|
||||||
|
torqueLateralControlToggle->setEnabled(_offroad && torque_allowed && !nnlcToggle->isToggled());
|
||||||
|
torqueLateralControlSettingsButton->setEnabled(torqueLateralControlToggle->isToggled());
|
||||||
|
|
||||||
blinkerPauseLateralSettings->refresh();
|
blinkerPauseLateralSettings->refresh();
|
||||||
|
|
||||||
offroad = _offroad;
|
offroad = _offroad;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/mads_settings.h"
|
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/mads_settings.h"
|
||||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/neural_network_lateral_control.h"
|
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/neural_network_lateral_control.h"
|
||||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/lane_change_settings.h"
|
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/lane_change_settings.h"
|
||||||
|
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_settings.h"
|
||||||
#include "selfdrive/ui/qt/util.h"
|
#include "selfdrive/ui/qt/util.h"
|
||||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h"
|
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h"
|
||||||
#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h"
|
#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h"
|
||||||
@@ -35,7 +36,6 @@ private:
|
|||||||
QStackedLayout* main_layout = nullptr;
|
QStackedLayout* main_layout = nullptr;
|
||||||
QWidget* sunnypilotScreen = nullptr;
|
QWidget* sunnypilotScreen = nullptr;
|
||||||
ScrollViewSP *sunnypilotScroller = nullptr;
|
ScrollViewSP *sunnypilotScroller = nullptr;
|
||||||
std::vector<ParamControl *> toggleOffroadOnly;
|
|
||||||
bool offroad;
|
bool offroad;
|
||||||
|
|
||||||
ParamControl *madsToggle;
|
ParamControl *madsToggle;
|
||||||
@@ -45,6 +45,9 @@ private:
|
|||||||
LaneChangeSettings *laneChangeWidget = nullptr;
|
LaneChangeSettings *laneChangeWidget = nullptr;
|
||||||
NeuralNetworkLateralControl *nnlcToggle = nullptr;
|
NeuralNetworkLateralControl *nnlcToggle = nullptr;
|
||||||
BlinkerPauseLateralSettings *blinkerPauseLateralSettings = nullptr;
|
BlinkerPauseLateralSettings *blinkerPauseLateralSettings = nullptr;
|
||||||
|
ParamControl *torqueLateralControlToggle;
|
||||||
|
PushButtonSP *torqueLateralControlSettingsButton;
|
||||||
|
TorqueLateralControlSettings *torqueLateralControlWidget = nullptr;
|
||||||
|
|
||||||
const QString MADS_BASE_DESC = tr("Enables independent engagements of Automatic Lane Centering (ALC) and Adaptive Cruise Control (ACC).");
|
const QString MADS_BASE_DESC = tr("Enables independent engagements of Automatic Lane Centering (ALC) and Adaptive Cruise Control (ACC).");
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
enum class SpeedLimitOffsetType {
|
||||||
|
NONE,
|
||||||
|
FIXED,
|
||||||
|
PERCENT,
|
||||||
|
};
|
||||||
|
|
||||||
|
inline const QString SpeedLimitOffsetTypeTexts[]{
|
||||||
|
QObject::tr("None"),
|
||||||
|
QObject::tr("Fixed"),
|
||||||
|
QObject::tr("Percent"),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SpeedLimitSourcePolicy {
|
||||||
|
CAR_ONLY,
|
||||||
|
MAP_ONLY,
|
||||||
|
CAR_FIRST,
|
||||||
|
MAP_FIRST,
|
||||||
|
COMBINED,
|
||||||
|
};
|
||||||
|
|
||||||
|
inline const QString SpeedLimitSourcePolicyTexts[]{
|
||||||
|
QObject::tr("Car\nOnly"),
|
||||||
|
QObject::tr("Map\nOnly"),
|
||||||
|
QObject::tr("Car\nFirst"),
|
||||||
|
QObject::tr("Map\nFirst"),
|
||||||
|
QObject::tr("Combined\nData")
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SpeedLimitMode {
|
||||||
|
OFF,
|
||||||
|
INFORMATION,
|
||||||
|
WARNING,
|
||||||
|
ASSIST,
|
||||||
|
};
|
||||||
|
|
||||||
|
inline const QString SpeedLimitModeTexts[]{
|
||||||
|
QObject::tr("Off"),
|
||||||
|
QObject::tr("Information"),
|
||||||
|
QObject::tr("Warning"),
|
||||||
|
QObject::tr("Assist"),
|
||||||
|
};
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user