mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-07-07 16:42:06 +08:00
Compare commits
87 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a9b205f7ea | |||
| 6cf172a26b | |||
| b01c106f3f | |||
| 737a6c4236 | |||
| 86cd1b238d | |||
| d6317ffd20 | |||
| 3ba52bc6fe | |||
| d7fd78050b | |||
| 8864b79a6e | |||
| e9f054b7ee | |||
| f429f3191f | |||
| 3df1b53fab | |||
| 6bb87174b9 | |||
| 6d356d520e | |||
| 73123aa400 | |||
| 7dfe03b7a3 | |||
| 12a4b1b561 | |||
| 7aac14e6fc | |||
| ae21d40a19 | |||
| 41abede7f6 | |||
| f653566803 | |||
| e8a39c4a74 | |||
| 517020ffb6 | |||
| a85f3ce11c | |||
| 014baf8e90 | |||
| 8050c56a43 | |||
| 0b826002e9 | |||
| 408d52d72a | |||
| aeaac22274 | |||
| f28cea759d | |||
| 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 | |||
| 772e62127e | |||
| e7a3ea1b32 | |||
| 87af129090 | |||
| f6cf1336ef | |||
| 51046dd7fd | |||
| 2c85f29a0b | |||
| 68af0c4a17 |
@@ -29,11 +29,11 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
target: /^(?!master$).*/
|
||||
target: /^(?!master-tici$).*/
|
||||
exclude: /sunnypilot:.*/
|
||||
change-to: ${{ github.base_ref }}
|
||||
already-exists-action: close_this
|
||||
already-exists-comment: "Your PR should be made against the `master` branch"
|
||||
already-exists-comment: "Your PR should be made against the `master-tici` branch"
|
||||
|
||||
update-pr-labels:
|
||||
name: Update fork's PR Labels
|
||||
|
||||
@@ -5,7 +5,7 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
BASE_IMAGE: sunnypilot-base
|
||||
BASE_IMAGE: sunnypilot-tici-base
|
||||
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
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ name: cereal validation
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- master-tici
|
||||
pull_request:
|
||||
paths:
|
||||
- 'cereal/**'
|
||||
@@ -16,7 +16,7 @@ on:
|
||||
type: string
|
||||
|
||||
concurrency:
|
||||
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 }}
|
||||
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 }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix: ${{fromJSON(needs.setup.outputs.ci_runs)}}
|
||||
uses: sunnypilot/sunnypilot/.github/workflows/ci_weekly_run.yaml@master
|
||||
uses: sunnypilot/sunnypilot/.github/workflows/ci_weekly_run.yaml@master-tici
|
||||
with:
|
||||
run_number: ${{ matrix.run_number }}
|
||||
|
||||
|
||||
@@ -12,6 +12,6 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
selfdrive_tests:
|
||||
uses: sunnypilot/sunnypilot/.github/workflows/selfdrive_tests.yaml@master
|
||||
uses: sunnypilot/sunnypilot/.github/workflows/selfdrive_tests.yaml@master-tici
|
||||
with:
|
||||
run_number: ${{ inputs.run_number }}
|
||||
|
||||
@@ -15,7 +15,7 @@ runs:
|
||||
scons -j$(nproc) --cache-populate"
|
||||
- name: Save scons cache
|
||||
uses: actions/cache/save@v4
|
||||
if: github.ref == 'refs/heads/master'
|
||||
if: github.ref == 'refs/heads/master-tici'
|
||||
with:
|
||||
path: .ci_cache/scons_cache
|
||||
key: scons-${{ runner.arch }}-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
||||
|
||||
@@ -3,7 +3,7 @@ name: docs
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- master-tici
|
||||
pull_request:
|
||||
workflow_call:
|
||||
inputs:
|
||||
@@ -12,7 +12,7 @@ on:
|
||||
required: true
|
||||
type: string
|
||||
concurrency:
|
||||
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 }}
|
||||
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 }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
@@ -35,13 +35,13 @@ jobs:
|
||||
|
||||
# Push to docs.comma.ai
|
||||
- uses: actions/checkout@v4
|
||||
if: github.ref == 'refs/heads/master' && github.repository == 'sunnypilot/sunnypilot'
|
||||
if: github.ref == 'refs/heads/master-tici' && github.repository == 'sunnypilot/sunnypilot'
|
||||
with:
|
||||
path: openpilot-docs
|
||||
ssh-key: ${{ secrets.OPENPILOT_DOCS_KEY }}
|
||||
repository: sunnypilot/sunnypilot-docs
|
||||
- name: Push
|
||||
if: github.ref == 'refs/heads/master' && github.repository == 'sunnypilot/sunnypilot'
|
||||
if: github.ref == 'refs/heads/master-tici' && github.repository == 'sunnypilot/sunnypilot'
|
||||
run: |
|
||||
set -x
|
||||
|
||||
|
||||
@@ -24,11 +24,11 @@ jobs:
|
||||
if: ${{ github.event_name != 'workflow_dispatch' }}
|
||||
uses: lewagon/wait-on-check-action@ccfb013c15c8afb7bf2b7c028fb74dc5a068cccc
|
||||
with:
|
||||
ref: master
|
||||
ref: master-tici
|
||||
wait-interval: 30
|
||||
running-workflow-name: 'build prebuilt'
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
check-regexp: ^((?!.*(build master-ci).*).)*$
|
||||
check-regexp: ^((?!.*(build __nightly).*).)*$
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
@@ -19,6 +19,7 @@ jobs:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
if: False
|
||||
steps:
|
||||
- uses: release-drafter/release-drafter@v6
|
||||
with:
|
||||
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
env:
|
||||
ImageOS: ubuntu24
|
||||
container:
|
||||
image: ghcr.io/sunnypilot/sunnypilot-base:latest
|
||||
image: ghcr.io/sunnypilot/sunnypilot-tici-base:latest
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'sunnypilot/sunnypilot'
|
||||
permissions:
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
if: ${{ github.event_name == 'schedule' }}
|
||||
uses: lewagon/wait-on-check-action@ccfb013c15c8afb7bf2b7c028fb74dc5a068cccc
|
||||
with:
|
||||
ref: master
|
||||
ref: master-tici
|
||||
wait-interval: 30
|
||||
running-workflow-name: 'build __nightly'
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -6,7 +6,7 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
BASE_IMAGE: sunnypilot-base
|
||||
BASE_IMAGE: sunnypilot-tici-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
|
||||
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
title: "[bot] Update translations"
|
||||
body: "Automatic PR from repo-maintenance -> update_translations"
|
||||
branch: "update-translations"
|
||||
base: "master"
|
||||
base: "master-tici"
|
||||
delete-branch: true
|
||||
labels: bot
|
||||
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
name: package_updates
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ghcr.io/sunnypilot/sunnypilot-base:latest
|
||||
image: ghcr.io/sunnypilot/sunnypilot-tici-base:latest
|
||||
if: github.repository == 'sunnypilot/sunnypilot'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -68,7 +68,7 @@ jobs:
|
||||
commit-message: Update Python packages
|
||||
title: '[bot] Update Python packages'
|
||||
branch: auto-package-updates
|
||||
base: master
|
||||
base: master-tici
|
||||
delete-branch: true
|
||||
body: 'Automatic PR from repo-maintenance -> package_updates'
|
||||
labels: bot
|
||||
|
||||
@@ -3,7 +3,7 @@ name: selfdrive
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- master-tici
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
workflow_call:
|
||||
@@ -14,12 +14,12 @@ on:
|
||||
type: string
|
||||
|
||||
concurrency:
|
||||
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 }}
|
||||
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 }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
PYTHONWARNINGS: error
|
||||
BASE_IMAGE: sunnypilot-base
|
||||
BASE_IMAGE: sunnypilot-tici-base
|
||||
AZURE_TOKEN: ${{ secrets.AZURE_COMMADATACI_OPENPILOTCI_TOKEN }}
|
||||
|
||||
DOCKER_LOGIN: docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -68,10 +68,10 @@ jobs:
|
||||
if: github.repository == 'sunnypilot/sunnypilot'
|
||||
timeout-minutes: 3
|
||||
run: |
|
||||
if [ "${{ github.ref }}" != "refs/heads/master" ]; then
|
||||
git fetch origin master:refs/remotes/origin/master
|
||||
if [ "${{ github.ref }}" != "refs/heads/master-tici" ]; then
|
||||
git fetch origin master-tici:refs/remotes/origin/master-tici
|
||||
|
||||
SUBMODULE_PATHS=$(git diff origin/master HEAD --name-only | grep -E '^[^/]+$' | while read path; do
|
||||
SUBMODULE_PATHS=$(git diff origin/master-tici HEAD --name-only | grep -E '^[^/]+$' | while read path; do
|
||||
if git ls-files --stage "$path" | grep -q "^160000"; then
|
||||
echo "$path"
|
||||
fi
|
||||
@@ -97,7 +97,7 @@ jobs:
|
||||
with:
|
||||
submodules: true
|
||||
- name: Setup docker push
|
||||
if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'sunnypilot/sunnypilot'
|
||||
if: github.ref == 'refs/heads/master-tici' && github.event_name != 'pull_request' && github.repository == 'sunnypilot/sunnypilot'
|
||||
run: |
|
||||
echo "PUSH_IMAGE=true" >> "$GITHUB_ENV"
|
||||
$DOCKER_LOGIN
|
||||
@@ -115,7 +115,9 @@ jobs:
|
||||
- run: echo "CACHE_COMMIT_DATE=$(git log -1 --pretty='format:%cd' --date=format:'%Y-%m-%d-%H:%M')" >> $GITHUB_ENV
|
||||
- name: Homebrew cache
|
||||
uses: ./.github/workflows/auto-cache
|
||||
if: false # disabling the cache for now because it is breaking macos builds...
|
||||
with:
|
||||
save: false # No need save here if we manually save it later conditionally
|
||||
path: ~/Library/Caches/Homebrew
|
||||
key: brew-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
@@ -128,7 +130,7 @@ jobs:
|
||||
HOMEBREW_DISPLAY_INSTALL_TIMES: 1
|
||||
- name: Save Homebrew cache
|
||||
uses: actions/cache/save@v4
|
||||
if: github.ref == 'refs/heads/master'
|
||||
if: github.ref == 'refs/heads/master-tici'
|
||||
with:
|
||||
path: ~/Library/Caches/Homebrew
|
||||
key: brew-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
||||
@@ -136,6 +138,7 @@ jobs:
|
||||
- name: Getting scons cache
|
||||
uses: ./.github/workflows/auto-cache
|
||||
with:
|
||||
save: false # No need save here if we manually save it later conditionally
|
||||
path: /tmp/scons_cache
|
||||
key: scons-${{ runner.arch }}-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
@@ -145,7 +148,7 @@ jobs:
|
||||
run: . .venv/bin/activate && scons -j$(nproc)
|
||||
- name: Save scons cache
|
||||
uses: actions/cache/save@v4
|
||||
if: github.ref == 'refs/heads/master'
|
||||
if: github.ref == 'refs/heads/master-tici'
|
||||
with:
|
||||
path: /tmp/scons_cache
|
||||
key: scons-${{ runner.arch }}-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
||||
@@ -304,5 +307,5 @@ jobs:
|
||||
- name: Upload Test Report
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: report-${{ inputs.run_number || '1' }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && 'master' || github.event.number }}
|
||||
name: report-${{ inputs.run_number || '1' }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master-tici' && 'master-tici' || github.event.number }}
|
||||
path: selfdrive/ui/tests/test_ui/report_1/screenshots
|
||||
|
||||
@@ -14,7 +14,7 @@ on:
|
||||
upstream_branch:
|
||||
description: 'Upstream branch to build from'
|
||||
required: true
|
||||
default: 'master'
|
||||
default: 'master-tici'
|
||||
type: string
|
||||
custom_name:
|
||||
description: 'Custom name for the model (no date, only name)'
|
||||
@@ -35,7 +35,7 @@ on:
|
||||
upstream_branch:
|
||||
description: 'Upstream branch to build from'
|
||||
required: true
|
||||
default: 'master'
|
||||
default: 'master-tici'
|
||||
type: string
|
||||
custom_name:
|
||||
description: 'Custom name for the model (no date, only name)'
|
||||
|
||||
@@ -8,14 +8,14 @@ env:
|
||||
PUBLIC_REPO_URL: "https://github.com/sunnypilot/sunnypilot"
|
||||
|
||||
# Branch configurations
|
||||
STAGING_SOURCE_BRANCH: 'master'
|
||||
STAGING_C3_SOURCE_BRANCH: 'master-tici' # vars.STAGING_C3_SOURCE_BRANCH could be used, set on repo settings.
|
||||
|
||||
# Runtime configuration
|
||||
SOURCE_BRANCH: "${{ github.head_ref || github.ref_name }}"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master, master-dev ]
|
||||
branches: [ master-tici ]
|
||||
tags: [ 'release/*' ]
|
||||
pull_request_target:
|
||||
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.
|
||||
restore-keys: |
|
||||
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.SOURCE_BRANCH }}
|
||||
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.STAGING_SOURCE_BRANCH }}
|
||||
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.STAGING_C3_SOURCE_BRANCH }}
|
||||
scons-${{ runner.os }}-${{ runner.arch }}
|
||||
|
||||
- name: Set environment variables
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
name: Build dev
|
||||
name: Build dev-c3-new
|
||||
|
||||
env:
|
||||
DEFAULT_SOURCE_BRANCH: "master"
|
||||
DEFAULT_TARGET_BRANCH: "master-dev"
|
||||
PR_LABEL: "dev"
|
||||
DEFAULT_SOURCE_BRANCH: "master-tici"
|
||||
DEFAULT_TARGET_BRANCH: "master-dev-c3-new"
|
||||
PR_LABEL: "dev-c3"
|
||||
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'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- master-tici
|
||||
pull_request_target:
|
||||
types: [ labeled ]
|
||||
branches:
|
||||
- 'master'
|
||||
- 'master-tici'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
source_branch:
|
||||
description: 'Source branch to reset from'
|
||||
required: true
|
||||
default: 'master'
|
||||
default: 'master-tici'
|
||||
type: string
|
||||
target_branch:
|
||||
description: 'Target branch to reset and squash into'
|
||||
required: true
|
||||
default: 'master-dev'
|
||||
default: 'master-dev-c3-new'
|
||||
type: string
|
||||
cancel_in_progress:
|
||||
description: 'Cancel any in-progress runs of this workflow'
|
||||
@@ -40,11 +40,7 @@ concurrency:
|
||||
jobs:
|
||||
reset-and-squash:
|
||||
runs-on: ubuntu-latest
|
||||
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'))))
|
||||
)
|
||||
if: False
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -55,7 +51,7 @@ jobs:
|
||||
uses: ./.github/workflows/wait-for-action # Path to where you place the action
|
||||
if: (
|
||||
(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'))))
|
||||
|| (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'))))
|
||||
)
|
||||
with:
|
||||
workflow: selfdrive_tests.yaml # The workflow file to monitor
|
||||
|
||||
@@ -2,19 +2,19 @@ name: "ui preview"
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- master-tici
|
||||
pull_request_target:
|
||||
types: [assigned, opened, synchronize, reopened, edited]
|
||||
branches:
|
||||
- 'master'
|
||||
- 'master-tici'
|
||||
paths:
|
||||
- 'selfdrive/ui/**'
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
UI_JOB_NAME: "Create UI Report"
|
||||
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' && github.sha || github.event.pull_request.head.sha }}
|
||||
REPORT_NAME: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master-tici' && 'master-tici' || github.event.number }}
|
||||
SHA: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master-tici' && github.sha || github.event.pull_request.head.sha }}
|
||||
BRANCH_NAME: "openpilot/pr-${{ github.event.number }}"
|
||||
|
||||
jobs:
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
name: report-1-${{ env.REPORT_NAME }}
|
||||
path: ${{ github.workspace }}/pr_ui
|
||||
|
||||
- name: Getting master ui
|
||||
- name: Getting master-tici ui
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: sunnypilot/ci-artifacts
|
||||
@@ -63,8 +63,8 @@ jobs:
|
||||
path: ${{ github.workspace }}/master_ui
|
||||
ref: openpilot_master_ui
|
||||
|
||||
- name: Saving new master ui
|
||||
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
|
||||
- name: Saving new master-tici ui
|
||||
if: github.ref == 'refs/heads/master-tici' && github.event_name == 'push'
|
||||
working-directory: ${{ github.workspace }}/master_ui
|
||||
run: |
|
||||
git checkout --orphan=new_master_ui
|
||||
@@ -93,9 +93,9 @@ jobs:
|
||||
|
||||
for ((i=0; i<${#A[*]}; i=i+1));
|
||||
do
|
||||
# Check if the master file exists
|
||||
# Check if the master-tici file exists
|
||||
if [ ! -f "${{ github.workspace }}/master_ui/${A[$i]}.png" ]; then
|
||||
# This is a new file in PR UI that doesn't exist in master
|
||||
# This is a new file in PR UI that doesn't exist in master-tici
|
||||
DIFF="${DIFF}<details open>"
|
||||
DIFF="${DIFF}<summary>${A[$i]} : \$\${\\color{cyan}\\text{NEW}}\$\$</summary>"
|
||||
DIFF="${DIFF}<table>"
|
||||
@@ -118,7 +118,7 @@ jobs:
|
||||
DIFF="${DIFF}<table>"
|
||||
|
||||
DIFF="${DIFF}<tr>"
|
||||
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> master-tici <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}</tr>"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM ghcr.io/sunnypilot/sunnypilot-base:latest
|
||||
FROM ghcr.io/sunnypilot/sunnypilot-tici-base:latest
|
||||
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
|
||||
|
||||
@@ -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).
|
||||
|
||||
## 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-c3-new` 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-tici` branch.
|
||||
|
||||
### If you want to use our newest branches (our rewrite)
|
||||
> [!TIP]
|
||||
@@ -31,25 +31,24 @@ Please refer to [Recommended Branches](#-recommended-branches) to find your pref
|
||||
* 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.
|
||||
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-c3-new.sunnypilot.ai```.
|
||||
3. Input the installation URL per [Recommended Branches](#-recommended-branches). Example: ```https://staging-tici.sunnypilot.ai```.
|
||||
4. Complete the rest of the installation following the onscreen instructions.
|
||||
|
||||
* sunnypilot already installed and you installed a version after 0.8.17?
|
||||
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.
|
||||
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-c3-new`
|
||||
4. Scroll to select the desired branch per Recommended Branches (see below). Example: `staging-tici`
|
||||
|
||||
|
||||
| Branch | Installation URL |
|
||||
|:----------------:|:---------------------------------------------:|
|
||||
| `staging-c3-new` | `https://staging-c3-new.sunnypilot.ai` |
|
||||
| `dev-c3-new` | `https://dev-c3-new.sunnypilot.ai` |
|
||||
| `custom-branch` | `https://install.sunnypilot.ai/{branch_name}` |
|
||||
| `release-c3-new` | **Not yet available**. |
|
||||
| Branch | Installation URL |
|
||||
|:---------------:|:---------------------------------------------:|
|
||||
| `staging-tici` | `https://staging-tici.sunnypilot.ai` |
|
||||
| `custom-branch` | `https://install.sunnypilot.ai/{branch_name}` |
|
||||
| `release-tici` | **Not yet available**. |
|
||||
|
||||
> [!TIP]
|
||||
> You can use sunnypilot/targetbranch as an install URL. Example: 'sunnypilot/staging-c3-new'.
|
||||
> You can use sunnypilot/targetbranch as an install URL. Example: 'sunnypilot/staging-tici'.
|
||||
|
||||
> [!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.
|
||||
|
||||
+77
-2
@@ -145,6 +145,11 @@ struct LongitudinalPlanSP @0xf35cc4560bbf6ec2 {
|
||||
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 {
|
||||
state @0 :DynamicExperimentalControlState;
|
||||
@@ -159,6 +164,7 @@ struct LongitudinalPlanSP @0xf35cc4560bbf6ec2 {
|
||||
|
||||
struct SmartCruiseControl {
|
||||
vision @0 :Vision;
|
||||
map @1 :Map;
|
||||
|
||||
struct Vision {
|
||||
state @0 :VisionState;
|
||||
@@ -170,6 +176,14 @@ struct LongitudinalPlanSP @0xf35cc4560bbf6ec2 {
|
||||
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.
|
||||
@@ -178,11 +192,65 @@ struct LongitudinalPlanSP @0xf35cc4560bbf6ec2 {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,14 +293,20 @@ struct OnroadEventSP @0xda96579883444c35 {
|
||||
pedalPressedAlertOnly @16;
|
||||
laneTurnLeft @17;
|
||||
laneTurnRight @18;
|
||||
speedLimitPreActive @19;
|
||||
speedLimitActive @20;
|
||||
speedLimitChanged @21;
|
||||
speedLimitPending @22;
|
||||
e2eChime @23;
|
||||
}
|
||||
}
|
||||
|
||||
struct CarParamsSP @0x80ae746ee2596b11 {
|
||||
flags @0 :UInt32; # flags for car specific quirks in sunnypilot
|
||||
safetyParam @1 : Int16; # flags for sunnypilot's custom safety flags
|
||||
pcmCruiseSpeed @3 :Bool = true;
|
||||
pcmCruiseSpeed @3 :Bool;
|
||||
intelligentCruiseButtonManagementAvailable @4 :Bool;
|
||||
enableGasInterceptor @5 :Bool;
|
||||
|
||||
neuralNetworkLateralControl @2 :NeuralNetworkLateralControl;
|
||||
|
||||
@@ -261,7 +335,7 @@ struct CarControlSP @0xa5cd762cd951a455 {
|
||||
|
||||
valueDEPRECATED @1 :Text; # The data type change may cause issues with backwards compatibility.
|
||||
}
|
||||
|
||||
|
||||
enum ParamType {
|
||||
string @0;
|
||||
bool @1;
|
||||
@@ -316,6 +390,7 @@ struct BackupManagerSP @0xf98d843bfd7004a3 {
|
||||
}
|
||||
|
||||
struct CarStateSP @0xb86e6369214c01c8 {
|
||||
speedLimit @0 :Float32;
|
||||
}
|
||||
|
||||
struct LiveMapDataSP @0xf416ec09499d9d19 {
|
||||
|
||||
+1
-1
@@ -2684,7 +2684,7 @@ struct Event {
|
||||
lateralPlanDEPRECATED @64 :LateralPlan;
|
||||
navModelDEPRECATED @104 :NavModelData;
|
||||
uiPlanDEPRECATED @106 :UiPlan;
|
||||
liveLocationKalmanDEPRECATED @72 :LiveLocationKalman;
|
||||
liveLocationKalman @72 :LiveLocationKalman;
|
||||
liveTracksDEPRECATED @16 :List(LiveTracksDEPRECATED);
|
||||
onroadEventsDEPRECATED @68: List(Car.OnroadEventDEPRECATED);
|
||||
}
|
||||
|
||||
@@ -89,6 +89,7 @@ _services: dict[str, tuple] = {
|
||||
"carStateSP": (True, 100., 10),
|
||||
"liveMapDataSP": (True, 1., 1),
|
||||
"modelDataV2SP": (True, 20.),
|
||||
"liveLocationKalman": (True, 20.),
|
||||
|
||||
# debug
|
||||
"uiDebug": (True, 0., 1),
|
||||
|
||||
+34
-2
@@ -94,6 +94,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"Offroad_NeosUpdate", {CLEAR_ON_MANAGER_START, JSON}},
|
||||
{"Offroad_NoFirmware", {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_UnregisteredHardware", {CLEAR_ON_MANAGER_START, JSON}},
|
||||
{"Offroad_UpdateFailed", {CLEAR_ON_MANAGER_START, JSON}},
|
||||
@@ -148,20 +149,29 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"DevUIInfo", {PERSISTENT | BACKUP, INT, "0"}},
|
||||
{"EnableCopyparty", {PERSISTENT | BACKUP, BOOL}},
|
||||
{"EnableGithubRunner", {PERSISTENT | BACKUP, BOOL}},
|
||||
{"GreenLightAlert", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"GithubRunnerSufficientVoltage", {CLEAR_ON_MANAGER_START , BOOL}},
|
||||
{"HideVEgoUI", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"IntelligentCruiseButtonManagement", {PERSISTENT | BACKUP , BOOL}},
|
||||
{"InteractivityTimeout", {PERSISTENT | BACKUP, INT, "0"}},
|
||||
{"IsDevelopmentBranch", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||
{"LastGPSPositionLLK", {PERSISTENT, STRING}},
|
||||
{"LeadDepartAlert", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"MaxTimeOffroad", {PERSISTENT | BACKUP, INT, "1800"}},
|
||||
{"ModelRunnerTypeCache", {CLEAR_ON_ONROAD_TRANSITION, INT}},
|
||||
{"OffroadMode", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||
{"Offroad_TiciSupport", {CLEAR_ON_MANAGER_START, JSON}},
|
||||
{"OnroadScreenOffBrightness", {PERSISTENT | BACKUP, INT, "100"}},
|
||||
{"OnroadScreenOffControl", {PERSISTENT | BACKUP, BOOL}},
|
||||
{"OnroadScreenOffTimer", {PERSISTENT | BACKUP, INT, "0"}},
|
||||
{"OnroadUploads", {PERSISTENT | BACKUP, BOOL, "1"}},
|
||||
{"QuickBootToggle", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"QuietMode", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"RainbowMode", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"ShowAdvancedControls", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"SmartCruiseControlVision", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"ShowTurnSignals", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"StandstillTimer", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"TrueVEgoUI", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
|
||||
// MADS params
|
||||
{"Mads", {PERSISTENT | BACKUP, BOOL, "1"}},
|
||||
@@ -187,7 +197,8 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"SunnylinkCache_Users", {PERSISTENT, STRING}},
|
||||
{"SunnylinkDongleId", {PERSISTENT, STRING}},
|
||||
{"SunnylinkdPid", {PERSISTENT, INT}},
|
||||
{"SunnylinkEnabled", {PERSISTENT, BOOL}},
|
||||
{"SunnylinkEnabled", {PERSISTENT, BOOL, "1"}},
|
||||
{"SunnylinkTempFault", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL, "0"}},
|
||||
|
||||
// Backup Manager params
|
||||
{"BackupManager_CreateBackup", {PERSISTENT, BOOL}},
|
||||
@@ -225,4 +236,25 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"OsmStateTitle", {PERSISTENT, STRING}},
|
||||
{"OsmWayTest", {PERSISTENT, 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 METER_TO_MILE = KM_TO_MILE / 1000.0;
|
||||
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))
|
||||
|
||||
|
||||
+6
-3
@@ -4,7 +4,7 @@
|
||||
|
||||
A supported vehicle is one that just works when you install a comma device. All supported cars provide a better experience than any stock system. Supported vehicles reference the US market unless otherwise specified.
|
||||
|
||||
# 334 Supported Cars
|
||||
# 337 Supported Cars
|
||||
|
||||
|Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|<a href="##"><img width=2000></a>Hardware Needed<br> |Video|Setup Video|
|
||||
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|
||||
@@ -83,7 +83,7 @@ A supported vehicle is one that just works when you install a comma device. All
|
||||
|Honda|Civic Hatchback 2017-18|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback 2017-18">Buy Here</a></sub></details>|||
|
||||
|Honda|Civic Hatchback 2019-21|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback 2019-21">Buy Here</a></sub></details>|||
|
||||
|Honda|Civic Hatchback 2022-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback 2022-24">Buy Here</a></sub></details>|<a href="https://youtu.be/ytiOT5lcp6Q" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|
||||
|Honda|Civic Hatchback Hybrid 2025|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback Hybrid 2025">Buy Here</a></sub></details>|||
|
||||
|Honda|Civic Hatchback Hybrid 2025-26|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback Hybrid 2025-26">Buy Here</a></sub></details>|||
|
||||
|Honda|Civic Hatchback Hybrid (Europe only) 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback Hybrid (Europe only) 2023">Buy Here</a></sub></details>|||
|
||||
|Honda|Civic Hybrid 2025|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hybrid 2025">Buy Here</a></sub></details>|||
|
||||
|Honda|Clarity 2018-21|Honda Sensing|openpilot|0 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector + Honda Clarity Proxy Board<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://shop.retropilot.org/product/honda-clarity-proxy-board-kit">Buy Here</a></sub></details>|||
|
||||
@@ -99,7 +99,9 @@ A supported vehicle is one that just works when you install a comma device. All
|
||||
|Honda|HR-V 2023-25|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda HR-V 2023-25">Buy Here</a></sub></details>|||
|
||||
|Honda|Insight 2019-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Insight 2019-22">Buy Here</a></sub></details>|||
|
||||
|Honda|Inspire 2018|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Inspire 2018">Buy Here</a></sub></details>|||
|
||||
|Honda|N-Box 2018|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|11 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda N-Box 2018">Buy Here</a></sub></details>|||
|
||||
|Honda|Odyssey 2018-20|Honda Sensing|openpilot|26 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Odyssey 2018-20">Buy Here</a></sub></details>|||
|
||||
|Honda|Odyssey 2021-25|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|43 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Odyssey 2021-25">Buy Here</a></sub></details>|||
|
||||
|Honda|Passport 2019-25|All|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Passport 2019-25">Buy Here</a></sub></details>|||
|
||||
|Honda|Pilot 2016-22|Honda Sensing|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Pilot 2016-22">Buy Here</a></sub></details>|||
|
||||
|Honda|Pilot 2023-25|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Pilot 2023-25">Buy Here</a></sub></details>|||
|
||||
@@ -163,6 +165,7 @@ A supported vehicle is one that just works when you install a comma device. All
|
||||
|Kia|EV6 (without HDA II) 2022-24[<sup>6</sup>](#footnotes)|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Kia EV6 (without HDA II) 2022-24">Buy Here</a></sub></details>|||
|
||||
|Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|6 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Forte 2019-21">Buy Here</a></sub></details>|||
|
||||
|Kia|Forte 2022-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Forte 2022-23">Buy Here</a></sub></details>|||
|
||||
|Kia|Forte Non-SCC 2019|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Forte Non-SCC 2019">Buy Here</a></sub></details>|||
|
||||
|Kia|K5 2021-24|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Kia K5 2021-24">Buy Here</a></sub></details>|||
|
||||
|Kia|K5 Hybrid 2020-22|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Kia K5 Hybrid 2020-22">Buy Here</a></sub></details>|||
|
||||
|Kia|K8 Hybrid (with HDA II) 2023[<sup>6</sup>](#footnotes)|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Kia K8 Hybrid (with HDA II) 2023">Buy Here</a></sub></details>|||
|
||||
@@ -259,7 +262,7 @@ A supported vehicle is one that just works when you install a comma device. All
|
||||
|Tesla[<sup>11</sup>](#footnotes)|Model 3 (with HW3) 2019-23[<sup>10</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Tesla A connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Tesla Model 3 (with HW3) 2019-23">Buy Here</a></sub></details>|||
|
||||
|Tesla[<sup>11</sup>](#footnotes)|Model 3 (with HW4) 2024-25[<sup>10</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Tesla B connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Tesla Model 3 (with HW4) 2024-25">Buy Here</a></sub></details>|||
|
||||
|Tesla[<sup>11</sup>](#footnotes)|Model Y (with HW3) 2020-23[<sup>10</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Tesla A connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Tesla Model Y (with HW3) 2020-23">Buy Here</a></sub></details>|||
|
||||
|Tesla[<sup>11</sup>](#footnotes)|Model Y (with HW4) 2024[<sup>10</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Tesla B connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Tesla Model Y (with HW4) 2024">Buy Here</a></sub></details>|||
|
||||
|Tesla[<sup>11</sup>](#footnotes)|Model Y (with HW4) 2024-25[<sup>10</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Tesla B connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Tesla Model Y (with HW4) 2024-25">Buy Here</a></sub></details>|||
|
||||
|Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Alphard 2019-20">Buy Here</a></sub></details>|||
|
||||
|Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Alphard Hybrid 2021">Buy Here</a></sub></details>|||
|
||||
|Toyota|Avalon 2016|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Avalon 2016">Buy Here</a></sub></details>|||
|
||||
|
||||
@@ -39,7 +39,7 @@ All of these are examples of good PRs:
|
||||
### 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.
|
||||
There's lot of bounties that don't require a comma 3X or a car.
|
||||
There's lot of bounties that don't require a comma 3/3X or a car.
|
||||
|
||||
## Pull Requests
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# connect to a comma 3X
|
||||
# connect to a comma 3/3X
|
||||
|
||||
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).
|
||||
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).
|
||||
|
||||
## Serial Console
|
||||
|
||||
On both the comma three and 3X, the serial console is accessible from the main OBD-C port.
|
||||
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.
|
||||
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.
|
||||
|
||||
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`
|
||||
|
||||
> [!NOTE]
|
||||
> The default port for ADB is 5555 on the comma 3X.
|
||||
> The default port for ADB is 5555 on the comma 3/3X.
|
||||
|
||||
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`.
|
||||
|
||||
## Replaying CAN data
|
||||
*Hardware required: jungle and comma 3X*
|
||||
*Hardware required: jungle and comma 3/3X*
|
||||
|
||||
1. Connect your PC to a jungle.
|
||||
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.
|
||||
|
||||
And if you have a comma 3X, we'll deploy the change to your device for testing.
|
||||
And if you have a comma 3/3X, we'll deploy the change to your device for testing.
|
||||
|
||||
## 1. Set up your development environment
|
||||
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ nav:
|
||||
- What is openpilot?: getting-started/what-is-openpilot.md
|
||||
- How-to:
|
||||
- Turn the speed blue: how-to/turn-the-speed-blue.md
|
||||
- Connect to a comma 3X: how-to/connect-to-comma.md
|
||||
- Connect to a comma 3/3X: how-to/connect-to-comma.md
|
||||
# - Make your first pull request: how-to/make-first-pr.md
|
||||
#- Replay a drive: how-to/replay-a-drive.md
|
||||
- Concepts:
|
||||
|
||||
+1
-1
Submodule opendbc_repo updated: f54d85c7d9...970fc577dd
+1
-1
Submodule panda updated: 69ab12ee2a...2a7914fa5a
@@ -31,13 +31,25 @@ while read hash submodule ref; do
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
git -C $submodule fetch --depth 100 origin master
|
||||
git -C $submodule branch -r --contains $hash | grep "origin/master"
|
||||
if [ "$?" -eq 0 ]; then
|
||||
echo "$submodule ok"
|
||||
# Check against master-tici for specific submodules, master for others
|
||||
if [ "$submodule" = "opendbc_repo" ] || [ "$submodule" = "panda" ]; then
|
||||
git -C $submodule fetch --depth 100 origin master-tici
|
||||
remote_hash=$(git -C $submodule rev-parse FETCH_HEAD)
|
||||
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
|
||||
echo "$submodule: $hash is not on master"
|
||||
exit 1
|
||||
git -C $submodule fetch --depth 100 origin master
|
||||
git -C $submodule branch -r --contains $hash | grep "origin/master"
|
||||
if [ "$?" -eq 0 ]; then
|
||||
echo "$submodule ok"
|
||||
else
|
||||
echo "$submodule: $hash is not on master"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done <<< $(git submodule status --recursive)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
if [ "$1" = "base" ]; then
|
||||
export DOCKER_IMAGE=sunnypilot-base
|
||||
export DOCKER_IMAGE=sunnypilot-tici-base
|
||||
export DOCKER_FILE=Dockerfile.sunnypilot_base
|
||||
elif [ "$1" = "prebuilt" ]; then
|
||||
export DOCKER_IMAGE=sunnypilot-prebuilt
|
||||
export DOCKER_IMAGE=sunnypilot-tici-prebuilt
|
||||
export DOCKER_FILE=Dockerfile.sunnypilot
|
||||
else
|
||||
echo "Invalid docker build image: '$1'"
|
||||
|
||||
@@ -71,7 +71,7 @@ class Car:
|
||||
|
||||
def __init__(self, CI=None, RI=None) -> None:
|
||||
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.can_rcv_cum_timeout_counter = 0
|
||||
@@ -124,7 +124,7 @@ class Car:
|
||||
|
||||
self.CP.alternativeExperience = 0
|
||||
# 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)
|
||||
|
||||
# Dynamic Experimental Control
|
||||
@@ -216,6 +216,7 @@ class Car:
|
||||
if can_rcv_valid and REPLAY:
|
||||
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)
|
||||
if self.sm['carControl'].enabled and not self.CC_prev.enabled:
|
||||
# Use CarState w/ buttons from the step selfdrived enables on
|
||||
|
||||
@@ -53,6 +53,7 @@ class VCruiseHelper(VCruiseHelperSP):
|
||||
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
|
||||
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.update_button_timers(CS, enabled)
|
||||
else:
|
||||
@@ -104,6 +105,12 @@ class VCruiseHelper(VCruiseHelperSP):
|
||||
if not self.button_change_states[button_type]["enabled"]:
|
||||
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)
|
||||
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
|
||||
|
||||
@@ -57,7 +57,7 @@ def convert_carControlSP(struct: capnp.lib.capnp._DynamicStructReader) -> struct
|
||||
struct_dataclass = structs.CarControlSP(**remove_deprecated({k: v for k, v in struct_dict.items() if not isinstance(k, dict)}))
|
||||
|
||||
struct_dataclass.mads = structs.ModularAssistiveDrivingSystem(**remove_deprecated(struct_dict.get('mads', {})))
|
||||
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.leadTwo = structs.LeadData(**remove_deprecated(struct_dict.get('leadTwo', {})))
|
||||
struct_dataclass.intelligentCruiseButtonManagement = structs.IntelligentCruiseButtonManagement(
|
||||
|
||||
@@ -60,7 +60,7 @@ class TestCarInterfaces:
|
||||
# Test controller initialization
|
||||
# TODO: wait until card refactor is merged to run controller a few times,
|
||||
# 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:
|
||||
LatControlAngle(car_params, car_params_sp, car_interface)
|
||||
elif car_params.lateralTuning.which() == 'pid':
|
||||
|
||||
@@ -44,12 +44,12 @@ class TestCruiseSpeed:
|
||||
assert simulation_steady_state == pytest.approx(cruise_speed, abs=.01), f'Did not reach {self.speed} m/s'
|
||||
|
||||
|
||||
# TODO: test pcmCruise
|
||||
@parameterized_class(('pcm_cruise',), [(False,)])
|
||||
# TODO: test pcmCruise and pcmCruiseSpeed
|
||||
@parameterized_class(('pcm_cruise', 'pcm_cruise_speed'), [(False, True)])
|
||||
class TestVCruiseHelper:
|
||||
def setup_method(self):
|
||||
self.CP = car.CarParams(pcmCruise=self.pcm_cruise)
|
||||
self.CP_SP = custom.CarParamsSP()
|
||||
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()
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ class Controls(ControlsExt, ModelStateBase):
|
||||
self.pose_calibrator = PoseCalibrator()
|
||||
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.LaC: LatControl
|
||||
if self.CP.steerControlType == car.CarParams.SteerControlType.angle:
|
||||
|
||||
@@ -48,6 +48,10 @@ class LatControlTorque(LatControl):
|
||||
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):
|
||||
# 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()
|
||||
if not active:
|
||||
output_torque = 0.0
|
||||
|
||||
@@ -10,8 +10,11 @@ CONTROL_N_T_IDX = ModelConstants.T_IDXS[:CONTROL_N]
|
||||
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):
|
||||
# Gas Interceptor
|
||||
cruise_standstill = cruise_standstill and not CP_SP.enableGasInterceptor
|
||||
|
||||
stopping_condition = should_stop
|
||||
starting_condition = (not should_stop 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
|
||||
|
||||
class LongControl:
|
||||
def __init__(self, CP):
|
||||
def __init__(self, CP, CP_SP):
|
||||
self.CP = CP
|
||||
self.CP_SP = CP_SP
|
||||
self.long_control_state = LongCtrlState.off
|
||||
self.pid = PIDController((CP.longitudinalTuning.kpBP, CP.longitudinalTuning.kpV),
|
||||
(CP.longitudinalTuning.kiBP, CP.longitudinalTuning.kiV),
|
||||
@@ -61,7 +65,7 @@ class LongControl:
|
||||
self.pid.neg_limit = accel_limits[0]
|
||||
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,
|
||||
CS.cruiseState.standstill)
|
||||
if self.long_control_state == LongCtrlState.off:
|
||||
|
||||
@@ -146,7 +146,7 @@ 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])
|
||||
accel_clip[1] = min(accel_clip[1], clipped_accel_coast_interp)
|
||||
|
||||
# Get new v_cruise and a_desired from Smart Cruise Control
|
||||
# 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:
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
from cereal import car
|
||||
from openpilot.common.gps import get_gps_location_service
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.realtime import Priority, config_realtime_process
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
@@ -16,14 +17,18 @@ def main():
|
||||
CP = messaging.log_from_bytes(params.get("CarParams", block=True), car.CarParams)
|
||||
cloudlog.info("plannerd got CarParams: %s", CP.brand)
|
||||
|
||||
gps_location_service = get_gps_location_service(params)
|
||||
|
||||
ldw = LaneDepartureWarning()
|
||||
longitudinal_planner = LongitudinalPlanner(CP)
|
||||
pm = messaging.PubMaster(['longitudinalPlan', 'driverAssistance', 'longitudinalPlanSP'])
|
||||
sm = messaging.SubMaster(['carControl', 'carState', 'controlsState', 'liveParameters', 'radarState', 'modelV2', 'selfdriveState'],
|
||||
poll='modelV2')
|
||||
sm = messaging.SubMaster(['carControl', 'carState', 'controlsState', 'liveParameters', 'radarState', 'modelV2', 'selfdriveState',
|
||||
'liveMapDataSP', 'carStateSP', gps_location_service],
|
||||
poll='carState')
|
||||
|
||||
while True:
|
||||
sm.update()
|
||||
longitudinal_planner.sla.update_car_state(sm['carState'])
|
||||
if sm.updated['modelV2']:
|
||||
longitudinal_planner.update(sm)
|
||||
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
|
||||
|
||||
|
||||
@@ -8,49 +8,52 @@ class TestLongControlStateTransition:
|
||||
|
||||
def test_stay_stopped(self):
|
||||
CP = car.CarParams.new_message()
|
||||
CP_SP = custom.CarParamsSP.new_message()
|
||||
active = True
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
assert next_state == LongCtrlState.pid
|
||||
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)
|
||||
assert next_state == LongCtrlState.off
|
||||
|
||||
def test_engage():
|
||||
CP = car.CarParams.new_message()
|
||||
CP_SP = custom.CarParamsSP.new_message()
|
||||
active = True
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
assert next_state == LongCtrlState.pid
|
||||
|
||||
def test_starting():
|
||||
CP = car.CarParams.new_message(startingState=True, vEgoStarting=0.5)
|
||||
CP_SP = custom.CarParamsSP.new_message()
|
||||
active = True
|
||||
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)
|
||||
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)
|
||||
assert next_state == LongCtrlState.pid
|
||||
|
||||
@@ -11,6 +11,7 @@ from openpilot.common.filter_simple import FirstOrderFilter
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
from openpilot.selfdrive.locationd.helpers import PointBuckets, ParameterEstimator, PoseCalibrator, Pose
|
||||
from openpilot.sunnypilot.livedelay.helpers import get_lat_delay
|
||||
from openpilot.sunnypilot.selfdrive.locationd.torqued_ext import TorqueEstimatorExt
|
||||
|
||||
HISTORY = 5 # secs
|
||||
POINTS_PER_BUCKET = 1500
|
||||
@@ -50,9 +51,10 @@ class TorqueBuckets(PointBuckets):
|
||||
break
|
||||
|
||||
|
||||
class TorqueEstimator(ParameterEstimator):
|
||||
class TorqueEstimator(ParameterEstimator, TorqueEstimatorExt):
|
||||
def __init__(self, CP, decimated=False, track_all_points=False):
|
||||
super().__init__()
|
||||
ParameterEstimator.__init__(self)
|
||||
TorqueEstimatorExt.__init__(self, CP)
|
||||
self.CP = CP
|
||||
self.hist_len = int(HISTORY / DT_MDL)
|
||||
self.lag = 0.0
|
||||
@@ -82,6 +84,8 @@ class TorqueEstimator(ParameterEstimator):
|
||||
|
||||
self.calibrator = PoseCalibrator()
|
||||
|
||||
TorqueEstimatorExt.initialize_custom_params(self, decimated)
|
||||
|
||||
self.reset()
|
||||
|
||||
initial_params = {
|
||||
@@ -260,6 +264,8 @@ def main(demo=False):
|
||||
t = sm.logMonoTime[which] * 1e-9
|
||||
estimator.handle_log(t, which, sm[which])
|
||||
|
||||
TorqueEstimatorExt.update_use_params(estimator)
|
||||
|
||||
# 4Hz driven by livePose
|
||||
if sm.frame % 5 == 0:
|
||||
pm.send('liveTorqueParameters', estimator.get_msg(valid=sm.all_checks()))
|
||||
|
||||
@@ -99,6 +99,11 @@ def main() -> None:
|
||||
cloudlog.event("pandad.flash_and_connect", count=count)
|
||||
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
|
||||
if no_internal_panda_count > 0:
|
||||
if no_internal_panda_count == 3:
|
||||
|
||||
Executable
BIN
Binary file not shown.
@@ -22,6 +22,8 @@ class TestPandad:
|
||||
if len(Panda.list()) == 0:
|
||||
self._run_test(60)
|
||||
|
||||
self.spi = HARDWARE.get_device_type() != 'tici'
|
||||
|
||||
def teardown_method(self):
|
||||
managed_processes['pandad'].stop()
|
||||
|
||||
@@ -104,9 +106,11 @@ class TestPandad:
|
||||
# - 0.2s pandad -> pandad
|
||||
# - plus some buffer
|
||||
print("startup times", ts, sum(ts) / len(ts))
|
||||
assert 0.1 < (sum(ts)/len(ts)) < 0.7
|
||||
assert 0.1 < (sum(ts)/len(ts)) < (0.7 if self.spi else 5.0)
|
||||
|
||||
def test_protocol_version_check(self):
|
||||
if not self.spi:
|
||||
pytest.skip("SPI test")
|
||||
# flash old fw
|
||||
fn = os.path.join(HERE, "bootstub.panda_h7_spiv0.bin")
|
||||
self._flash_bootstub_and_test(fn, expect_mismatch=True)
|
||||
|
||||
@@ -6,6 +6,7 @@ import random
|
||||
|
||||
import cereal.messaging as messaging
|
||||
from cereal.services import SERVICE_LIST
|
||||
from openpilot.system.hardware import HARDWARE
|
||||
from openpilot.selfdrive.test.helpers import with_processes
|
||||
from openpilot.selfdrive.pandad.tests.test_pandad_loopback import setup_pandad, send_random_can_messages
|
||||
|
||||
@@ -15,6 +16,8 @@ JUNGLE_SPAM = "JUNGLE_SPAM" in os.environ
|
||||
class TestBoarddSpi:
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
if HARDWARE.get_device_type() == 'tici':
|
||||
pytest.skip("only for spi pandas")
|
||||
os.environ['STARTED'] = '1'
|
||||
os.environ['SPI_ERR_PROB'] = '0.001'
|
||||
if not JUNGLE_SPAM:
|
||||
|
||||
@@ -29,6 +29,10 @@
|
||||
"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
|
||||
},
|
||||
"Offroad_StorageMissing": {
|
||||
"text": "NVMe drive not mounted.",
|
||||
"severity": 1
|
||||
},
|
||||
"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.",
|
||||
"severity": 0
|
||||
|
||||
@@ -21,6 +21,7 @@ from openpilot.selfdrive.selfdrived.helpers import ExcessiveActuationCheck
|
||||
from openpilot.selfdrive.selfdrived.state import StateMachine
|
||||
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.sunnypilot.mads.mads import ModularAssistiveDrivingSystem
|
||||
@@ -96,7 +97,7 @@ class SelfdriveD(CruiseHelper):
|
||||
'carOutput', 'driverMonitoringState', 'longitudinalPlan', 'livePose', 'liveDelay',
|
||||
'managerState', 'liveParameters', 'radarState', 'liveTorqueParameters',
|
||||
'controlsState', 'carControl', 'driverAssistance', 'alertDebug', 'userBookmark', 'audioFeedback',
|
||||
'modelDataV2SP'] + \
|
||||
'modelDataV2SP', 'longitudinalPlanSP'] + \
|
||||
self.camera_packets + self.sensor_packets + self.gps_packets,
|
||||
ignore_alive=ignore, ignore_avg_freq=ignore,
|
||||
ignore_valid=ignore, frequency=int(1/DT_CTRL))
|
||||
@@ -135,7 +136,12 @@ class SelfdriveD(CruiseHelper):
|
||||
self.state_machine = StateMachine()
|
||||
self.rk = Ratekeeper(100, print_delay_threshold=None)
|
||||
|
||||
self.ignored_processes = {'mapd', }
|
||||
# some comma three with NVMe experience NVMe dropouts mid-drive that
|
||||
# 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', 'mapd'}
|
||||
|
||||
# Determine startup event
|
||||
is_remote = build_metadata.openpilot.comma_remote or build_metadata.openpilot.sunnypilot_remote
|
||||
@@ -159,7 +165,7 @@ class SelfdriveD(CruiseHelper):
|
||||
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)
|
||||
|
||||
@@ -205,6 +211,7 @@ class SelfdriveD(CruiseHelper):
|
||||
|
||||
if not self.CP.notCar:
|
||||
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
|
||||
if CS.canValid:
|
||||
@@ -444,7 +451,7 @@ class SelfdriveD(CruiseHelper):
|
||||
self.events.add(EventName.personalityChanged)
|
||||
self.experimental_mode_switched = False
|
||||
|
||||
self.icbm.run(CS, self.sm['carControl'], self.is_metric)
|
||||
self.icbm.run(CS, self.sm['carControl'], self.sm['longitudinalPlanSP'], self.is_metric)
|
||||
|
||||
def data_sample(self):
|
||||
_car_state = messaging.recv_one(self.car_state_sock)
|
||||
|
||||
@@ -67,6 +67,9 @@ class Plant:
|
||||
lp = messaging.new_message('liveParameters')
|
||||
car_control = messaging.new_message('carControl')
|
||||
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
|
||||
self.v_lead_prev = v_lead
|
||||
|
||||
@@ -133,7 +136,10 @@ class Plant:
|
||||
'controlsState': control.controlsState,
|
||||
'selfdriveState': ss.selfdriveState,
|
||||
'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.acceleration = self.planner.output_a_target
|
||||
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
|
||||
# 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
|
||||
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 = [
|
||||
migrate_sensorEvents,
|
||||
migrate_carParams,
|
||||
@@ -37,7 +38,6 @@ def migrate_all(lr: LogIterable, manager_states: bool = False, panda_states: boo
|
||||
migrate_carOutput,
|
||||
migrate_controlsState,
|
||||
migrate_carState,
|
||||
migrate_liveLocationKalman,
|
||||
migrate_liveTracks,
|
||||
migrate_driverAssistance,
|
||||
migrate_drivingModelData,
|
||||
@@ -51,6 +51,8 @@ def migrate_all(lr: LogIterable, manager_states: bool = False, panda_states: boo
|
||||
migrations.extend([migrate_pandaStates, migrate_peripheralState])
|
||||
if camera_states:
|
||||
migrations.append(migrate_cameraStates)
|
||||
if live_location_kalman:
|
||||
migrations.append(migrate_liveLocationKalman)
|
||||
|
||||
return migrate(lr, migrations)
|
||||
|
||||
|
||||
@@ -496,7 +496,7 @@ CONFIGS = [
|
||||
pubs=[
|
||||
"cameraOdometry", "accelerometer", "gyroscope", "liveCalibration", "carState"
|
||||
],
|
||||
subs=["livePose"],
|
||||
subs=["liveLocationKalman", "livePose"],
|
||||
ignore=["logMonoTime"],
|
||||
should_recv_callback=MessageBasedRcvCallback("cameraOdometry"),
|
||||
tolerance=NUMPY_TOLERANCE,
|
||||
|
||||
@@ -47,11 +47,12 @@ void HudRenderer::draw(QPainter &p, const QRect &surface_rect) {
|
||||
bg.setColorAt(1, QColor::fromRgbF(0, 0, 0, 0));
|
||||
p.fillRect(0, 0, surface_rect.width(), UI_HEADER_HEIGHT, bg);
|
||||
|
||||
|
||||
#ifndef SUNNYPILOT
|
||||
if (is_cruise_available) {
|
||||
drawSetSpeed(p, surface_rect);
|
||||
}
|
||||
drawCurrentSpeed(p, surface_rect);
|
||||
#endif
|
||||
|
||||
p.restore();
|
||||
}
|
||||
|
||||
@@ -4,8 +4,10 @@
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/qt/onroad/annotated_camera.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/onroad/alerts.h"
|
||||
#define UIState UIStateSP
|
||||
#define AnnotatedCameraWidget AnnotatedCameraWidgetSP
|
||||
#define OnroadAlerts OnroadAlertsSP
|
||||
#else
|
||||
#include "selfdrive/ui/qt/onroad/annotated_camera.h"
|
||||
#endif
|
||||
|
||||
@@ -24,6 +24,7 @@ qt_src = [
|
||||
"sunnypilot/qt/offroad/offroad_home.cc",
|
||||
"sunnypilot/qt/offroad/settings/developer_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/longitudinal_panel.cc",
|
||||
"sunnypilot/qt/offroad/settings/max_time_offroad.cc",
|
||||
@@ -37,6 +38,7 @@ qt_src = [
|
||||
"sunnypilot/qt/offroad/settings/trips_panel.cc",
|
||||
"sunnypilot/qt/offroad/settings/vehicle_panel.cc",
|
||||
"sunnypilot/qt/offroad/settings/visuals_panel.cc",
|
||||
"sunnypilot/qt/onroad/alerts.cc",
|
||||
"sunnypilot/qt/onroad/annotated_camera.cc",
|
||||
"sunnypilot/qt/onroad/buttons.cc",
|
||||
"sunnypilot/qt/onroad/developer_ui/developer_ui.cc",
|
||||
@@ -50,10 +52,14 @@ lateral_panel_qt_src = [
|
||||
"sunnypilot/qt/offroad/settings/lateral/lane_change_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/torque_lateral_control_custom_params.cc",
|
||||
"sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_settings.cc",
|
||||
]
|
||||
|
||||
longitudinal_panel_qt_src = [
|
||||
"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 = [
|
||||
@@ -88,9 +94,13 @@ brand_settings_qt_src = [
|
||||
"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_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
|
||||
|
||||
Export('sp_widgets_src', 'sp_qt_src', "sp_qt_util")
|
||||
|
||||
@@ -25,8 +25,8 @@ const QMap<QString, QString> Brightness::brightness_options = {
|
||||
|
||||
Brightness::Brightness() : OptionControlSP(
|
||||
"Brightness",
|
||||
tr("Brightness"),
|
||||
tr("Overrides the brightness of the device."),
|
||||
tr("Global Brightness"),
|
||||
tr("Overrides the brightness of the device. This applies to both onroad and offroad screens. "),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
{0, 11}, 1, true, &brightness_options) {
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ DevicePanelSP::DevicePanelSP(SettingsWindowSP *parent) : DevicePanel(parent) {
|
||||
{"regulatoryBtn", tr("Regulatory"), ""},
|
||||
{"translateBtn", tr("Language"), ""},
|
||||
{"resetParams", tr("Reset Settings"), ""},
|
||||
{"onroadUploadsBtn", tr("Onroad Uploads"), "OnroadUploads"}
|
||||
};
|
||||
|
||||
int row = 0, col = 0;
|
||||
@@ -75,12 +76,14 @@ DevicePanelSP::DevicePanelSP(SettingsWindowSP *parent) : DevicePanel(parent) {
|
||||
|
||||
connect(buttons["resetParams"], &PushButtonSP::clicked, this, &DevicePanelSP::resetSettings);
|
||||
|
||||
connect(buttons["onroadUploadsBtn"], &PushButtonSP::clicked, buttons["onroadUploadsBtn"], &PushButtonSP::updateButton);
|
||||
|
||||
// Max Time Offroad
|
||||
maxTimeOffroad = new MaxTimeOffroad();
|
||||
connect(maxTimeOffroad, &OptionControlSP::updateLabels, maxTimeOffroad, &MaxTimeOffroad::refresh);
|
||||
addItem(maxTimeOffroad);
|
||||
|
||||
toggleDeviceBootMode = new ButtonParamControlSP("DeviceBootMode", tr("Wake-Up Behavior"), "", "", {"Default", "Offroad"}, 375, true);
|
||||
toggleDeviceBootMode = new ButtonParamControlSP("DeviceBootMode", tr("Wake-Up Behavior"), "", "", {"Default", "Offroad"}, 375, true);
|
||||
addItem(toggleDeviceBootMode);
|
||||
|
||||
connect(toggleDeviceBootMode, &ButtonParamControlSP::buttonClicked, this, [=](int index) {
|
||||
@@ -88,22 +91,6 @@ DevicePanelSP::DevicePanelSP(SettingsWindowSP *parent) : DevicePanel(parent) {
|
||||
updateState();
|
||||
});
|
||||
|
||||
interactivityTimeout = new OptionControlSP("InteractivityTimeout", tr("Interactivity Timeout"),
|
||||
tr("Apply a custom timeout for settings UI."
|
||||
"\nThis is the time after which settings UI closes automatically if user is not interacting with the screen."),
|
||||
"", {0, 120}, 10, true, nullptr, false);
|
||||
|
||||
connect(interactivityTimeout, &OptionControlSP::updateLabels, [=]() {
|
||||
updateState();
|
||||
});
|
||||
|
||||
addItem(interactivityTimeout);
|
||||
|
||||
// Brightness
|
||||
brightness = new Brightness();
|
||||
connect(brightness, &OptionControlSP::updateLabels, brightness, &Brightness::refresh);
|
||||
addItem(brightness);
|
||||
|
||||
addItem(device_grid_layout);
|
||||
|
||||
// offroad mode and power buttons
|
||||
@@ -129,9 +116,8 @@ DevicePanelSP::DevicePanelSP(SettingsWindowSP *parent) : DevicePanel(parent) {
|
||||
offroadBtn->setFixedWidth(power_layout->sizeHint().width());
|
||||
QObject::connect(offroadBtn, &PushButtonSP::clicked, this, &DevicePanelSP::setOffroadMode);
|
||||
|
||||
QVBoxLayout *power_group_layout = new QVBoxLayout();
|
||||
power_group_layout = new QVBoxLayout();
|
||||
power_group_layout->setSpacing(25);
|
||||
power_group_layout->addWidget(offroadBtn, 0, Qt::AlignHCenter);
|
||||
power_group_layout->addLayout(power_layout);
|
||||
|
||||
addItem(power_group_layout);
|
||||
@@ -141,9 +127,10 @@ DevicePanelSP::DevicePanelSP(SettingsWindowSP *parent) : DevicePanel(parent) {
|
||||
poweroffBtn,
|
||||
offroadBtn,
|
||||
buttons["quietModeBtn"],
|
||||
buttons["onroadUploadsBtn"],
|
||||
};
|
||||
|
||||
QObject::connect(uiState(), &UIState::offroadTransition, [=](bool offroad) {
|
||||
QObject::connect(uiState(), &UIState::offroadTransition, [=](bool _offroad) {
|
||||
for (auto btn : findChildren<PushButtonSP*>()) {
|
||||
bool always_enabled = std::find(always_enabled_btns.begin(), always_enabled_btns.end(), btn) != always_enabled_btns.end();
|
||||
|
||||
@@ -151,6 +138,8 @@ DevicePanelSP::DevicePanelSP(SettingsWindowSP *parent) : DevicePanel(parent) {
|
||||
btn->setEnabled(offroad);
|
||||
}
|
||||
}
|
||||
offroad = _offroad;
|
||||
updateState();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -201,7 +190,7 @@ void DevicePanelSP::updateState() {
|
||||
}
|
||||
|
||||
bool offroad_mode_param = params.getBool("OffroadMode");
|
||||
offroadBtn->setText(offroad_mode_param ? tr("Exit Always Offroad") : tr("Always Offroad"));
|
||||
offroadBtn->setText(offroad_mode_param ? tr("Exit Always Offroad") : tr("Enable Always Offroad"));
|
||||
offroadBtn->setStyleSheet(offroad_mode_param ? alwaysOffroadStyle : autoOffroadStyle);
|
||||
|
||||
DeviceSleepModeStatus currStatus = DeviceSleepModeStatus::DEFAULT;
|
||||
@@ -210,10 +199,9 @@ void DevicePanelSP::updateState() {
|
||||
}
|
||||
toggleDeviceBootMode->setDescription(deviceSleepModeDescription(currStatus));
|
||||
|
||||
QString timeoutValue = QString::fromStdString(params.get("InteractivityTimeout"));
|
||||
if (timeoutValue == "0" || timeoutValue.isEmpty()) {
|
||||
interactivityTimeout->setLabel("Default");
|
||||
if (offroad and not offroad_mode_param) {
|
||||
power_group_layout->insertWidget(0, offroadBtn, 0, Qt::AlignHCenter);
|
||||
} else {
|
||||
interactivityTimeout->setLabel(timeoutValue + "s");
|
||||
AddWidgetAt(0, offroadBtn);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/max_time_offroad.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/brightness.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
|
||||
|
||||
@@ -32,8 +31,8 @@ private:
|
||||
PushButtonSP *offroadBtn;
|
||||
MaxTimeOffroad *maxTimeOffroad;
|
||||
ButtonParamControlSP *toggleDeviceBootMode;
|
||||
Brightness *brightness;
|
||||
OptionControlSP *interactivityTimeout;
|
||||
QVBoxLayout *power_group_layout;
|
||||
bool offroad;
|
||||
|
||||
const QString alwaysOffroadStyle = R"(
|
||||
PushButtonSP {
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* 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 QVBoxLayout();
|
||||
mainFrame->setLayout(mainFrameLayout);
|
||||
mainFrameLayout->setSpacing(30);
|
||||
mainFrameLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
onroadScreenOffTimer = new OptionControlSP(
|
||||
"OnroadScreenOffTimer",
|
||||
"Onroad Brightness Delay",
|
||||
"",
|
||||
"",
|
||||
{0, 11}, 1, true, &onroadScreenOffTimerOptions);
|
||||
|
||||
onroadScreenBrightness = new OptionControlSP(
|
||||
"OnroadScreenOffBrightness",
|
||||
"Onroad Brightness",
|
||||
"",
|
||||
"",
|
||||
{0, 100}, 10, true);
|
||||
|
||||
connect(onroadScreenOffTimer, &OptionControlSP::updateLabels, this, &OnroadScreenBrightnessControl::refresh);
|
||||
connect(onroadScreenBrightness, &OptionControlSP::updateLabels, this, &OnroadScreenBrightnessControl::refresh);
|
||||
mainFrameLayout->addWidget(onroadScreenBrightness);
|
||||
mainFrameLayout->addWidget(onroadScreenOffTimer);
|
||||
|
||||
addItem(mainFrame);
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
void OnroadScreenBrightnessControl::refresh() {
|
||||
// Driving Screen Off Timer
|
||||
int valTimer = std::atoi(params.get("OnroadScreenOffTimer").c_str());
|
||||
std::string labelTimer = (valTimer < 60 ? std::to_string(valTimer) + "s" : std::to_string(valTimer / 60) + "m");
|
||||
onroadScreenOffTimer->setLabel(QString::fromStdString(labelTimer));
|
||||
|
||||
// Driving Screen Off Brightness
|
||||
std::string valBrightness = params.get("OnroadScreenOffBrightness");
|
||||
std::string labelBrightness = (valBrightness == "0" ? " Screen Off" : valBrightness + "%");
|
||||
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,65 @@
|
||||
/**
|
||||
* 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("Onroad Screen: Reduced Brightness"),
|
||||
tr("Turn off device screen or reduce brightness after driving starts. "
|
||||
"It automatically brightens again when screen is touched or a visible alert is displayed."),
|
||||
"",
|
||||
this);
|
||||
list->addItem(onroadScreenBrightnessControl);
|
||||
list->addItem(horizontal_line());
|
||||
|
||||
// Global Brightness
|
||||
brightness = new Brightness();
|
||||
connect(brightness, &OptionControlSP::updateLabels, brightness, &Brightness::refresh);
|
||||
list->addItem(brightness);
|
||||
list->addItem(horizontal_line());
|
||||
|
||||
// Interactivity Timeout
|
||||
interactivityTimeout = new OptionControlSP("InteractivityTimeout", tr("Interactivity Timeout"),
|
||||
tr("Apply a custom timeout for settings UI."
|
||||
"\nThis is the time after which settings UI closes automatically if user is not interacting with the screen."),
|
||||
"", {0, 120}, 10, true, nullptr, false);
|
||||
|
||||
connect(interactivityTimeout, &OptionControlSP::updateLabels, [=]() {
|
||||
refresh();
|
||||
});
|
||||
list->addItem(interactivityTimeout);
|
||||
|
||||
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();
|
||||
|
||||
QString timeoutValue = QString::fromStdString(params.get("InteractivityTimeout"));
|
||||
if (timeoutValue == "0" || timeoutValue.isEmpty()) {
|
||||
interactivityTimeout->setLabel("Default");
|
||||
} else {
|
||||
interactivityTimeout->setLabel(timeoutValue + "s");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 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/brightness.h"
|
||||
#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;
|
||||
Brightness *brightness;
|
||||
OptionControlSP *interactivityTimeout;
|
||||
};
|
||||
@@ -52,12 +52,16 @@ void MadsSettings::updateToggles(bool _offroad) {
|
||||
);
|
||||
|
||||
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_sp;
|
||||
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::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.putBool("MadsUnifiedEngagementMode", true);
|
||||
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/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 {
|
||||
REMAIN_ACTIVE = 0,
|
||||
|
||||
+11
-3
@@ -10,14 +10,15 @@
|
||||
NeuralNetworkLateralControl::NeuralNetworkLateralControl() :
|
||||
ParamControl("NeuralNetworkLateralControl", tr("Neural Network Lateral Control (NNLC)"), "", "") {
|
||||
setConfirmation(true, false);
|
||||
updateToggle();
|
||||
updateToggle(offroad);
|
||||
}
|
||||
|
||||
void NeuralNetworkLateralControl::updateToggle() {
|
||||
void NeuralNetworkLateralControl::updateToggle(bool _offroad) {
|
||||
QString statusInitText = "<font color='yellow'>" + STATUS_CHECK_COMPATIBILITY + "</font>";
|
||||
QString notLoadedText = "<font color='yellow'>" + STATUS_NOT_LOADED + "</font>";
|
||||
QString loadedText = "<font color=#00ff00>" + STATUS_LOADED + "</font>";
|
||||
|
||||
bool allowed = true;
|
||||
auto cp_bytes = params.get("CarParamsPersistent");
|
||||
auto cp_sp_bytes = params.get("CarParamsSPPersistent");
|
||||
if (!cp_bytes.empty() && !cp_sp_bytes.empty()) {
|
||||
@@ -31,7 +32,7 @@ void NeuralNetworkLateralControl::updateToggle() {
|
||||
if (CP.getSteerControlType() == cereal::CarParams::SteerControlType::ANGLE) {
|
||||
params.remove("NeuralNetworkLateralControl");
|
||||
setDescription(nnffDescriptionBuilder(STATUS_NOT_AVAILABLE));
|
||||
setEnabled(false);
|
||||
allowed = false;
|
||||
} else {
|
||||
QString nn_model_name = QString::fromStdString(CP_SP.getNeuralNetworkLateralControl().getModel().getName());
|
||||
QString nn_fuzzy = CP_SP.getNeuralNetworkLateralControl().getFuzzyFingerprint() ?
|
||||
@@ -56,4 +57,11 @@ void NeuralNetworkLateralControl::updateToggle() {
|
||||
if (getDescription() != getBaseDescription()) {
|
||||
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();
|
||||
|
||||
public slots:
|
||||
void updateToggle();
|
||||
void updateToggle(bool _offroad);
|
||||
|
||||
private:
|
||||
Params params;
|
||||
bool offroad;
|
||||
|
||||
// Status messages
|
||||
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());
|
||||
|
||||
// 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
|
||||
nnlcToggle = new NeuralNetworkLateralControl();
|
||||
list->addItem(nnlcToggle);
|
||||
@@ -86,12 +116,10 @@ LateralPanel::LateralPanel(SettingsWindowSP *parent) : QFrame(parent) {
|
||||
nnlcToggle->hideDescription();
|
||||
}
|
||||
|
||||
nnlcToggle->updateToggle();
|
||||
nnlcToggle->updateToggle(offroad);
|
||||
updateToggles(offroad);
|
||||
});
|
||||
|
||||
toggleOffroadOnly = {
|
||||
madsToggle, nnlcToggle,
|
||||
};
|
||||
QObject::connect(uiState(), &UIState::offroadTransition, this, &LateralPanel::updateToggles);
|
||||
|
||||
sunnypilotScroller = new ScrollViewSP(list, this);
|
||||
@@ -100,6 +128,7 @@ LateralPanel::LateralPanel(SettingsWindowSP *parent) : QFrame(parent) {
|
||||
main_layout->addWidget(sunnypilotScreen);
|
||||
main_layout->addWidget(madsWidget);
|
||||
main_layout->addWidget(laneChangeWidget);
|
||||
main_layout->addWidget(torqueLateralControlWidget);
|
||||
|
||||
setStyleSheet(R"(
|
||||
#back_btn {
|
||||
@@ -120,7 +149,7 @@ LateralPanel::LateralPanel(SettingsWindowSP *parent) : QFrame(parent) {
|
||||
}
|
||||
|
||||
void LateralPanel::showEvent(QShowEvent *event) {
|
||||
nnlcToggle->updateToggle();
|
||||
nnlcToggle->updateToggle(offroad);
|
||||
updateToggles(offroad);
|
||||
}
|
||||
|
||||
@@ -129,27 +158,40 @@ void LateralPanel::hideEvent(QHideEvent *event) {
|
||||
}
|
||||
|
||||
void LateralPanel::updateToggles(bool _offroad) {
|
||||
for (auto *toggle : toggleOffroadOnly) {
|
||||
toggle->setEnabled(_offroad);
|
||||
}
|
||||
|
||||
bool torque_allowed = true;
|
||||
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_sp;
|
||||
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::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));
|
||||
} else {
|
||||
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 {
|
||||
madsToggle->setDescription(descriptionBuilder(STATUS_MADS_CHECK_COMPATIBILITY, MADS_BASE_DESC));
|
||||
|
||||
params.remove("EnforceTorqueControl");
|
||||
torque_allowed = false;
|
||||
}
|
||||
|
||||
madsToggle->setEnabled(_offroad);
|
||||
madsSettingsButton->setEnabled(madsToggle->isToggled());
|
||||
|
||||
torqueLateralControlToggle->setEnabled(_offroad && torque_allowed && !nnlcToggle->isToggled());
|
||||
torqueLateralControlSettingsButton->setEnabled(torqueLateralControlToggle->isToggled());
|
||||
|
||||
blinkerPauseLateralSettings->refresh();
|
||||
|
||||
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/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/torque_lateral_control_settings.h"
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h"
|
||||
@@ -35,7 +36,6 @@ private:
|
||||
QStackedLayout* main_layout = nullptr;
|
||||
QWidget* sunnypilotScreen = nullptr;
|
||||
ScrollViewSP *sunnypilotScroller = nullptr;
|
||||
std::vector<ParamControl *> toggleOffroadOnly;
|
||||
bool offroad;
|
||||
|
||||
ParamControl *madsToggle;
|
||||
@@ -45,6 +45,9 @@ private:
|
||||
LaneChangeSettings *laneChangeWidget = nullptr;
|
||||
NeuralNetworkLateralControl *nnlcToggle = 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).");
|
||||
|
||||
|
||||
@@ -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"),
|
||||
};
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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 <QScrollBar>
|
||||
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_policy.h"
|
||||
|
||||
SpeedLimitPolicy::SpeedLimitPolicy(QWidget *parent) : QWidget(parent) {
|
||||
QVBoxLayout *main_layout = new QVBoxLayout(this);
|
||||
main_layout->setContentsMargins(0, 0, 0, 0);
|
||||
main_layout->setSpacing(0);
|
||||
|
||||
// Back button
|
||||
PanelBackButton *back = new PanelBackButton(tr("Back"));
|
||||
connect(back, &QPushButton::clicked, [=]() { emit backPress(); });
|
||||
main_layout->addWidget(back, 0, Qt::AlignLeft);
|
||||
|
||||
main_layout->addSpacing(10);
|
||||
|
||||
ListWidgetSP *list = new ListWidgetSP(this);
|
||||
|
||||
std::vector<QString> speed_limit_policy_texts{
|
||||
SpeedLimitSourcePolicyTexts[static_cast<int>(SpeedLimitSourcePolicy::CAR_ONLY)],
|
||||
SpeedLimitSourcePolicyTexts[static_cast<int>(SpeedLimitSourcePolicy::MAP_ONLY)],
|
||||
SpeedLimitSourcePolicyTexts[static_cast<int>(SpeedLimitSourcePolicy::CAR_FIRST)],
|
||||
SpeedLimitSourcePolicyTexts[static_cast<int>(SpeedLimitSourcePolicy::MAP_FIRST)],
|
||||
SpeedLimitSourcePolicyTexts[static_cast<int>(SpeedLimitSourcePolicy::COMBINED)]
|
||||
};
|
||||
speed_limit_policy = new ButtonParamControlSP(
|
||||
"SpeedLimitPolicy",
|
||||
tr("Speed Limit Source"),
|
||||
"",
|
||||
"",
|
||||
speed_limit_policy_texts,
|
||||
250);
|
||||
list->addItem(speed_limit_policy);
|
||||
connect(speed_limit_policy, &ButtonParamControlSP::buttonClicked, this, &SpeedLimitPolicy::refresh);
|
||||
|
||||
speedLimitPolicyScroller = new ScrollViewSP(list, this);
|
||||
main_layout->addWidget(speedLimitPolicyScroller);
|
||||
refresh();
|
||||
};
|
||||
|
||||
void SpeedLimitPolicy::refresh() {
|
||||
SpeedLimitSourcePolicy policy_param = static_cast<SpeedLimitSourcePolicy>(std::atoi(params.get("SpeedLimitPolicy").c_str()));
|
||||
speed_limit_policy->setDescription(sourceDescription(policy_param));
|
||||
}
|
||||
|
||||
void SpeedLimitPolicy::showEvent(QShowEvent *event) {
|
||||
speedLimitPolicyScroller->verticalScrollBar()->setValue(0);
|
||||
refresh();
|
||||
speed_limit_policy->showDescription();
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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/longitudinal/speed_limit/helpers.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h"
|
||||
|
||||
class SpeedLimitPolicy : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SpeedLimitPolicy(QWidget *parent = nullptr);
|
||||
void refresh();
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
signals:
|
||||
void backPress();
|
||||
|
||||
private:
|
||||
Params params;
|
||||
ButtonParamControlSP *speed_limit_policy;
|
||||
ScrollViewSP *speedLimitPolicyScroller;
|
||||
|
||||
static QString sourceDescription(SpeedLimitSourcePolicy type = SpeedLimitSourcePolicy::CAR_ONLY) {
|
||||
QString car_only = tr("⦿ Car Only: Use Speed Limit data only from Car");
|
||||
QString map_only = tr("⦿ Map Only: Use Speed Limit data only from OpenStreetMaps");
|
||||
QString car_first = tr("⦿ Car First: Use Speed Limit data from Car if available, else use from OpenStreetMaps");
|
||||
QString map_first = tr("⦿ Map First: Use Speed Limit data from OpenStreetMaps if available, else use from Car");
|
||||
QString combined = tr("⦿ Combined: Use combined Speed Limit data from Car & OpenStreetMaps");
|
||||
|
||||
if (type == SpeedLimitSourcePolicy::CAR_ONLY) {
|
||||
car_only = "<font color='white'><b>" + car_only + "</b></font>";
|
||||
} else if (type == SpeedLimitSourcePolicy::MAP_ONLY) {
|
||||
map_only = "<font color='white'><b>" + map_only + "</b></font>";
|
||||
} else if (type == SpeedLimitSourcePolicy::CAR_FIRST) {
|
||||
car_first = "<font color='white'><b>" + car_first + "</b></font>";
|
||||
} else if (type == SpeedLimitSourcePolicy::MAP_FIRST) {
|
||||
map_first = "<font color='white'><b>" + map_first + "</b></font>";
|
||||
} else {
|
||||
combined = "<font color='white'><b>" + combined + "</b></font>";
|
||||
}
|
||||
|
||||
return QString("%1<br>%2<br>%3<br>%4<br>%5")
|
||||
.arg(car_only)
|
||||
.arg(map_only)
|
||||
.arg(car_first)
|
||||
.arg(map_first)
|
||||
.arg(combined);
|
||||
}
|
||||
};
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* 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/longitudinal/speed_limit/speed_limit_settings.h"
|
||||
|
||||
SpeedLimitSettings::SpeedLimitSettings(QWidget *parent) : QStackedWidget(parent) {
|
||||
subPanelFrame = new QFrame();
|
||||
QVBoxLayout *subPanelLayout = new QVBoxLayout(subPanelFrame);
|
||||
subPanelLayout->setContentsMargins(0, 0, 0, 0);
|
||||
subPanelLayout->setSpacing(0);
|
||||
|
||||
// Back button
|
||||
PanelBackButton *back = new PanelBackButton(tr("Back"));
|
||||
connect(back, &QPushButton::clicked, [=]() { emit backPress(); });
|
||||
subPanelLayout->addWidget(back, 0, Qt::AlignLeft);
|
||||
|
||||
subPanelLayout->addSpacing(20);
|
||||
|
||||
ListWidgetSP *list = new ListWidgetSP(this, false);
|
||||
|
||||
speedLimitPolicyScreen = new SpeedLimitPolicy(this);
|
||||
|
||||
std::vector<QString> speed_limit_mode_texts{
|
||||
SpeedLimitModeTexts[static_cast<int>(SpeedLimitMode::OFF)],
|
||||
SpeedLimitModeTexts[static_cast<int>(SpeedLimitMode::INFORMATION)],
|
||||
SpeedLimitModeTexts[static_cast<int>(SpeedLimitMode::WARNING)],
|
||||
SpeedLimitModeTexts[static_cast<int>(SpeedLimitMode::ASSIST)],
|
||||
};
|
||||
speed_limit_mode_settings = new ButtonParamControlSP(
|
||||
"SpeedLimitMode",
|
||||
tr("Speed Limit"),
|
||||
"",
|
||||
"",
|
||||
speed_limit_mode_texts,
|
||||
380);
|
||||
list->addItem(speed_limit_mode_settings);
|
||||
|
||||
list->addItem(horizontal_line());
|
||||
list->addItem(vertical_space());
|
||||
|
||||
speedLimitSource = new PushButtonSP(tr("Customize Source"));
|
||||
connect(speedLimitSource, &QPushButton::clicked, [&]() {
|
||||
speedLimitScroller->setLastScrollPosition();
|
||||
setCurrentWidget(speedLimitPolicyScreen);
|
||||
speedLimitPolicyScreen->refresh();
|
||||
});
|
||||
connect(speedLimitPolicyScreen, &SpeedLimitPolicy::backPress, [&]() {
|
||||
speedLimitScroller->restoreScrollPosition();
|
||||
setCurrentWidget(subPanelFrame);
|
||||
showEvent(new QShowEvent());
|
||||
});
|
||||
|
||||
speedLimitSource->setFixedWidth(720);
|
||||
list->addItem(speedLimitSource);
|
||||
|
||||
list->addItem(vertical_space(0));
|
||||
list->addItem(horizontal_line());
|
||||
|
||||
QFrame *offsetFrame = new QFrame(this);
|
||||
QVBoxLayout *offsetLayout = new QVBoxLayout(offsetFrame);
|
||||
|
||||
std::vector<QString> speed_limit_offset_texts{
|
||||
SpeedLimitOffsetTypeTexts[static_cast<int>(SpeedLimitOffsetType::NONE)],
|
||||
SpeedLimitOffsetTypeTexts[static_cast<int>(SpeedLimitOffsetType::FIXED)],
|
||||
SpeedLimitOffsetTypeTexts[static_cast<int>(SpeedLimitOffsetType::PERCENT)]
|
||||
};
|
||||
speed_limit_offset_settings = new ButtonParamControlSP(
|
||||
"SpeedLimitOffsetType",
|
||||
tr("Speed Limit Offset"),
|
||||
"",
|
||||
"",
|
||||
speed_limit_offset_texts,
|
||||
500);
|
||||
|
||||
offsetLayout->addWidget(speed_limit_offset_settings);
|
||||
|
||||
speed_limit_offset = new OptionControlSP(
|
||||
"SpeedLimitValueOffset",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
{-30, 30}
|
||||
);
|
||||
offsetLayout->addWidget(speed_limit_offset);
|
||||
|
||||
list->addItem(offsetFrame);
|
||||
|
||||
connect(speed_limit_mode_settings, &ButtonParamControlSP::buttonClicked, this, &SpeedLimitSettings::refresh);
|
||||
connect(speed_limit_offset, &OptionControlSP::updateLabels, this, &SpeedLimitSettings::refresh);
|
||||
connect(speed_limit_offset_settings, &ButtonParamControlSP::showDescriptionEvent, speed_limit_offset, &OptionControlSP::showDescription);
|
||||
connect(speed_limit_offset_settings, &ButtonParamControlSP::buttonClicked, this, &SpeedLimitSettings::refresh);
|
||||
|
||||
refresh();
|
||||
speedLimitScroller = new ScrollViewSP(list, this);
|
||||
subPanelLayout->addWidget(speedLimitScroller);
|
||||
addWidget(subPanelFrame);
|
||||
addWidget(speedLimitPolicyScreen);
|
||||
setCurrentWidget(subPanelFrame);
|
||||
}
|
||||
|
||||
void SpeedLimitSettings::refresh() {
|
||||
bool is_metric_param = params.getBool("IsMetric");
|
||||
SpeedLimitMode speed_limit_mode_param = static_cast<SpeedLimitMode>(std::atoi(params.get("SpeedLimitMode").c_str()));
|
||||
SpeedLimitOffsetType offset_type_param = static_cast<SpeedLimitOffsetType>(std::atoi(params.get("SpeedLimitOffsetType").c_str()));
|
||||
QString offsetLabel = QString::fromStdString(params.get("SpeedLimitValueOffset"));
|
||||
|
||||
bool has_longitudinal_control;
|
||||
bool intelligent_cruise_button_management_available;
|
||||
auto cp_bytes = params.get("CarParamsPersistent");
|
||||
auto cp_sp_bytes = params.get("CarParamsSPPersistent");
|
||||
if (!cp_bytes.empty() && !cp_sp_bytes.empty()) {
|
||||
AlignedBuffer aligned_buf;
|
||||
AlignedBuffer aligned_buf_sp;
|
||||
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::CarParamsSP::Reader CP_SP = cmsg_sp.getRoot<cereal::CarParamsSP>();
|
||||
|
||||
has_longitudinal_control = hasLongitudinalControl(CP);
|
||||
intelligent_cruise_button_management_available = CP_SP.getIntelligentCruiseButtonManagementAvailable();
|
||||
} else {
|
||||
has_longitudinal_control = false;
|
||||
intelligent_cruise_button_management_available = false;
|
||||
}
|
||||
|
||||
speed_limit_mode_settings->setDescription(modeDescription(speed_limit_mode_param));
|
||||
speed_limit_offset->setDescription(offsetDescription(offset_type_param));
|
||||
|
||||
if (offset_type_param == SpeedLimitOffsetType::PERCENT) {
|
||||
offsetLabel += "%";
|
||||
} else if (offset_type_param == SpeedLimitOffsetType::FIXED) {
|
||||
offsetLabel += QString(" %1").arg(is_metric_param ? "km/h" : "mph");
|
||||
}
|
||||
|
||||
if (offset_type_param == SpeedLimitOffsetType::NONE) {
|
||||
speed_limit_offset->setVisible(false);
|
||||
} else {
|
||||
speed_limit_offset->setVisible(true);
|
||||
speed_limit_offset->setLabel(offsetLabel);
|
||||
speed_limit_offset->showDescription();
|
||||
}
|
||||
|
||||
if (has_longitudinal_control || intelligent_cruise_button_management_available) {
|
||||
speed_limit_mode_settings->setEnableSelectedButtons(true, convertSpeedLimitModeValues(getSpeedLimitModeValues()));
|
||||
} else {
|
||||
speed_limit_mode_settings->setEnableSelectedButtons(true, convertSpeedLimitModeValues(
|
||||
{SpeedLimitMode::OFF,SpeedLimitMode::INFORMATION, SpeedLimitMode::WARNING}));
|
||||
}
|
||||
|
||||
speed_limit_mode_settings->showDescription();
|
||||
speed_limit_offset->showDescription();
|
||||
}
|
||||
|
||||
void SpeedLimitSettings::showEvent(QShowEvent *event) {
|
||||
refresh();
|
||||
}
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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/offroad/settings/longitudinal/speed_limit/helpers.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_policy.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h"
|
||||
|
||||
class SpeedLimitSettings : public QStackedWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SpeedLimitSettings(QWidget *parent = nullptr);
|
||||
void refresh();
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
signals:
|
||||
void backPress();
|
||||
|
||||
private:
|
||||
Params params;
|
||||
ScrollViewSP *speedLimitScroller;
|
||||
QFrame *subPanelFrame;
|
||||
ButtonParamControlSP *speed_limit_mode_settings;
|
||||
PushButtonSP *speedLimitSource;
|
||||
SpeedLimitPolicy *speedLimitPolicyScreen;
|
||||
ButtonParamControlSP *speed_limit_offset_settings;
|
||||
OptionControlSP *speed_limit_offset;
|
||||
|
||||
static QString offsetDescription(SpeedLimitOffsetType type = SpeedLimitOffsetType::NONE) {
|
||||
QString none_str = tr("⦿ None: No Offset");
|
||||
QString fixed_str = tr("⦿ Fixed: Adds a fixed offset [Speed Limit + Offset]");
|
||||
QString percent_str = tr("⦿ Percent: Adds a percent offset [Speed Limit + (Offset % Speed Limit)]");
|
||||
|
||||
if (type == SpeedLimitOffsetType::FIXED) {
|
||||
fixed_str = "<font color='white'><b>" + fixed_str + "</b></font>";
|
||||
} else if (type == SpeedLimitOffsetType::PERCENT) {
|
||||
percent_str = "<font color='white'><b>" + percent_str + "</b></font>";
|
||||
} else {
|
||||
none_str = "<font color='white'><b>" + none_str + "</b></font>";
|
||||
}
|
||||
|
||||
return QString("%1<br>%2<br>%3")
|
||||
.arg(none_str)
|
||||
.arg(fixed_str)
|
||||
.arg(percent_str);
|
||||
}
|
||||
|
||||
static QString modeDescription(SpeedLimitMode mode = SpeedLimitMode::OFF) {
|
||||
QString off_str = tr("⦿ Off: Disables the Speed Limit functions.");
|
||||
QString info_str = tr("⦿ Information: Displays the current road's speed limit.");
|
||||
QString warning_str = tr("⦿ Warning: Provides a warning when exceeding the current road's speed limit.");
|
||||
QString assist_str = tr("⦿ Assist: Adjusts the vehicle's cruise speed based on the current road's speed limit when operating the +/- buttons.");
|
||||
|
||||
if (mode == SpeedLimitMode::ASSIST) {
|
||||
assist_str = "<font color='white'><b>" + assist_str + "</b></font>";
|
||||
} else if (mode == SpeedLimitMode::WARNING) {
|
||||
warning_str = "<font color='white'><b>" + warning_str + "</b></font>";
|
||||
} else if (mode == SpeedLimitMode::INFORMATION) {
|
||||
info_str = "<font color='white'><b>" + info_str + "</b></font>";
|
||||
} else {
|
||||
off_str = "<font color='white'><b>" + off_str + "</b></font>";
|
||||
}
|
||||
|
||||
return QString("%1<br>%2<br>%3<br>%4")
|
||||
.arg(off_str)
|
||||
.arg(info_str)
|
||||
.arg(warning_str)
|
||||
.arg(assist_str);
|
||||
}
|
||||
|
||||
static std::vector<SpeedLimitMode> getSpeedLimitModeValues() {
|
||||
std::vector<SpeedLimitMode> values;
|
||||
for (int i = static_cast<int>(SpeedLimitMode::OFF);
|
||||
i <= static_cast<int>(SpeedLimitMode::ASSIST); ++i) {
|
||||
values.push_back(static_cast<SpeedLimitMode>(i));
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
static std::vector<int> convertSpeedLimitModeValues(const std::vector<SpeedLimitMode> &modes) {
|
||||
std::vector<int> values;
|
||||
for (const auto& mode : modes) {
|
||||
values.push_back(static_cast<int>(mode));
|
||||
}
|
||||
return values;
|
||||
}
|
||||
};
|
||||
@@ -8,6 +8,21 @@
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal_panel.h"
|
||||
|
||||
LongitudinalPanel::LongitudinalPanel(QWidget *parent) : QWidget(parent) {
|
||||
setStyleSheet(R"(
|
||||
#back_btn {
|
||||
font-size: 50px;
|
||||
margin: 0px;
|
||||
padding: 15px;
|
||||
border-width: 0;
|
||||
border-radius: 30px;
|
||||
color: #dddddd;
|
||||
background-color: #393939;
|
||||
}
|
||||
#back_btn:pressed {
|
||||
background-color: #4a4a4a;
|
||||
}
|
||||
)");
|
||||
|
||||
main_layout = new QStackedLayout(this);
|
||||
ListWidget *list = new ListWidget(this, false);
|
||||
|
||||
@@ -35,12 +50,33 @@ LongitudinalPanel::LongitudinalPanel(QWidget *parent) : QWidget(parent) {
|
||||
"");
|
||||
list->addItem(SmartCruiseControlVision);
|
||||
|
||||
SmartCruiseControlMap = new ParamControl(
|
||||
"SmartCruiseControlMap",
|
||||
tr("Smart Cruise Control - Map"),
|
||||
tr("Use map data to estimate the appropriate speed to drive through turns ahead."),
|
||||
"");
|
||||
list->addItem(SmartCruiseControlMap);
|
||||
|
||||
customAccIncrement = new CustomAccIncrement("CustomAccIncrementsEnabled", tr("Custom ACC Speed Increments"), "", "", this);
|
||||
list->addItem(customAccIncrement);
|
||||
|
||||
QObject::connect(uiState(), &UIState::offroadTransition, this, &LongitudinalPanel::refresh);
|
||||
|
||||
speedLimitSettings = new PushButtonSP(tr("Speed Limit"), 750, this);
|
||||
connect(speedLimitSettings, &QPushButton::clicked, [&]() {
|
||||
cruisePanelScroller->setLastScrollPosition();
|
||||
main_layout->setCurrentWidget(speedLimitScreen);
|
||||
});
|
||||
list->addItem(speedLimitSettings);
|
||||
|
||||
speedLimitScreen = new SpeedLimitSettings(this);
|
||||
connect(speedLimitScreen, &SpeedLimitSettings::backPress, [=]() {
|
||||
cruisePanelScroller->restoreScrollPosition();
|
||||
main_layout->setCurrentWidget(cruisePanelScreen);
|
||||
});
|
||||
|
||||
main_layout->addWidget(cruisePanelScreen);
|
||||
main_layout->addWidget(speedLimitScreen);
|
||||
main_layout->setCurrentWidget(cruisePanelScreen);
|
||||
refresh(offroad);
|
||||
}
|
||||
@@ -105,6 +141,7 @@ void LongitudinalPanel::refresh(bool _offroad) {
|
||||
customAccIncrement->refresh();
|
||||
|
||||
SmartCruiseControlVision->setEnabled(has_longitudinal_control || icbm_allowed);
|
||||
SmartCruiseControlMap->setEnabled(has_longitudinal_control || icbm_allowed);
|
||||
|
||||
offroad = _offroad;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/custom_acc_increment.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_settings.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h"
|
||||
|
||||
@@ -31,5 +32,8 @@ private:
|
||||
QWidget *cruisePanelScreen = nullptr;
|
||||
CustomAccIncrement *customAccIncrement = nullptr;
|
||||
ParamControl *SmartCruiseControlVision;
|
||||
ParamControl *SmartCruiseControlMap;
|
||||
ParamControl *intelligentCruiseButtonManagement = nullptr;
|
||||
SpeedLimitSettings *speedLimitScreen;
|
||||
PushButtonSP *speedLimitSettings;
|
||||
};
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "common/swaglog.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/util.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h"
|
||||
|
||||
OsmPanel::OsmPanel(QWidget *parent) : QFrame(parent) {
|
||||
@@ -91,24 +92,30 @@ ButtonControlSP *OsmPanel::setupOsmDownloadButton(QWidget *parent) {
|
||||
locationTitles.push_back(std::get<0>(loc));
|
||||
}
|
||||
|
||||
const QString selection = MultiOptionDialog::getSelection(tr("Country"), locationTitles, currentTitle, this);
|
||||
if (!selection.isEmpty()) {
|
||||
params.put("OsmLocal", "1");
|
||||
params.put("OsmLocationTitle", selection.toStdString());
|
||||
for (auto &loc: locations) {
|
||||
if (std::get<0>(loc) == selection) {
|
||||
params.put("OsmLocationName", std::get<1>(loc).toStdString());
|
||||
break;
|
||||
InputDialog d(tr("Search Country"), this, tr("Enter search keywords, or leave blank to list all countries."), false);
|
||||
d.setMinLength(0);
|
||||
const int ret = d.exec();
|
||||
if (ret) {
|
||||
const QString selection = search(d.text(), locationTitles, tr("Select Country"));
|
||||
if (!selection.isEmpty()) {
|
||||
params.put("OsmLocal", "1");
|
||||
params.put("OsmLocationTitle", selection.toStdString());
|
||||
for (auto &loc: locations) {
|
||||
if (std::get<0>(loc) == selection) {
|
||||
params.put("OsmLocationName", std::get<1>(loc).toStdString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (params.get("OsmLocationName") == "US") {
|
||||
usStatesBtn->click();
|
||||
return;
|
||||
} else if (selection != "== None ==") {
|
||||
if (showConfirmationDialog(parent)) {
|
||||
osm_download_in_progress = true;
|
||||
params.putBool("OsmDbUpdatesCheck", true);
|
||||
updateLabels();
|
||||
if (params.get("OsmLocationName") == "US") {
|
||||
usStatesBtn->click();
|
||||
return;
|
||||
}
|
||||
if (selection != "== None ==") {
|
||||
if (showConfirmationDialog(parent)) {
|
||||
osm_download_in_progress = true;
|
||||
params.putBool("OsmDbUpdatesCheck", true);
|
||||
updateLabels();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -135,20 +142,25 @@ ButtonControlSP *OsmPanel::setupUsStatesButton(QWidget *parent) {
|
||||
locationTitles.push_back(std::get<0>(loc));
|
||||
}
|
||||
|
||||
const QString selection = MultiOptionDialog::getSelection(tr("State"), locationTitles, currentTitle, this);
|
||||
if (!selection.isEmpty()) {
|
||||
params.put("OsmStateTitle", selection.toStdString());
|
||||
for (auto &loc: locations) {
|
||||
if (std::get<0>(loc) == selection) {
|
||||
params.put("OsmStateName", std::get<1>(loc).toStdString());
|
||||
break;
|
||||
InputDialog d(tr("Search State"), this, tr("Enter search keywords, or leave blank to list all states."), false);
|
||||
d.setMinLength(0);
|
||||
const int ret = d.exec();
|
||||
if (ret) {
|
||||
const QString selection = search(d.text(), locationTitles, tr("Select State"));
|
||||
if (!selection.isEmpty()) {
|
||||
params.put("OsmStateTitle", selection.toStdString());
|
||||
for (auto &loc: locations) {
|
||||
if (std::get<0>(loc) == selection) {
|
||||
params.put("OsmStateName", std::get<1>(loc).toStdString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
usStatesBtn->setValue(selection);
|
||||
if (showConfirmationDialog(parent)) {
|
||||
osm_download_in_progress = true;
|
||||
params.putBool("OsmDbUpdatesCheck", true);
|
||||
updateLabels();
|
||||
}
|
||||
}
|
||||
usStatesBtn->setValue(selection);
|
||||
if (showConfirmationDialog(parent)) {
|
||||
osm_download_in_progress = true;
|
||||
params.putBool("OsmDbUpdatesCheck", true);
|
||||
updateLabels();
|
||||
}
|
||||
}
|
||||
updateLabels();
|
||||
@@ -281,3 +293,15 @@ void OsmPanel::updateMapSize() {
|
||||
mapSizeFuture = QtConcurrent::run(getDirSize, MAP_PATH);
|
||||
}
|
||||
}
|
||||
|
||||
QString OsmPanel::search(const QString &query, const QStringList &list, const QString &prompt_text) {
|
||||
QStringList lst_results = searchFromList(query, list);
|
||||
QString selection;
|
||||
|
||||
if (lst_results.isEmpty()) {
|
||||
ConfirmationDialog::alert(tr("No results found for keywords: %1").arg(query), this);
|
||||
return selection;
|
||||
}
|
||||
selection = MultiOptionDialog::getSelection(prompt_text, lst_results, "", this);
|
||||
return selection;
|
||||
}
|
||||
|
||||
@@ -76,6 +76,7 @@ private:
|
||||
void updateDownloadProgress();
|
||||
static int extractIntFromJson(const QJsonObject &json, const QString &key);
|
||||
QString processUpdateStatus(bool pending_update_check, int total_files, int downloaded_files, const QJsonObject &json, bool failed_state);
|
||||
QString search(const QString &query, const QStringList &list, const QString &prompt_text);
|
||||
|
||||
ConfirmationDialog *confirmationDialog;
|
||||
LabelControlSP *mapdVersion;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/developer_panel.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/display_panel.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/software_panel.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink_panel.h"
|
||||
@@ -87,6 +88,7 @@ SettingsWindowSP::SettingsWindowSP(QWidget *parent) : SettingsWindow(parent) {
|
||||
PanelInfo(" " + tr("Steering"), new LateralPanel(this), "../../sunnypilot/selfdrive/assets/offroad/icon_lateral.png"),
|
||||
PanelInfo(" " + tr("Cruise"), new LongitudinalPanel(this), "../assets/icons/speed_limit.png"),
|
||||
PanelInfo(" " + tr("Visuals"), new VisualsPanel(this), "../../sunnypilot/selfdrive/assets/offroad/icon_visuals.png"),
|
||||
PanelInfo(" " + tr("Display"), new DisplayPanel(this), "../../sunnypilot/selfdrive/assets/offroad/icon_display.png"),
|
||||
PanelInfo(" " + tr("OSM"), new OsmPanel(this), "../../sunnypilot/selfdrive/assets/offroad/icon_map.png"),
|
||||
PanelInfo(" " + tr("Trips"), new TripsPanel(this), "../../sunnypilot/selfdrive/assets/offroad/icon_trips.png"),
|
||||
PanelInfo(" " + tr("Vehicle"), new VehiclePanel(this), "../../sunnypilot/selfdrive/assets/offroad/icon_vehicle.png"),
|
||||
|
||||
@@ -25,21 +25,69 @@ VisualsPanel::VisualsPanel(QWidget *parent) : QWidget(parent) {
|
||||
"BlindSpot",
|
||||
tr("Show Blind Spot Warnings"),
|
||||
tr("Enabling this will display warnings when a vehicle is detected in your blind spot as long as your car has BSM supported."),
|
||||
"../assets/offroad/icon_monitoring.png",
|
||||
"",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"RainbowMode",
|
||||
tr("Enable Tesla Rainbow Mode"),
|
||||
RainbowizeWords(tr("A beautiful rainbow effect on the path the model wants to take.")) + "<br/><i>" + tr("It")+ " <b>" + tr("does not") + "</b> " + tr("affect driving in any way.") + "</i>",
|
||||
"../assets/offroad/icon_monitoring.png",
|
||||
"",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"StandstillTimer",
|
||||
tr("Enable Standstill Timer"),
|
||||
tr("Show a timer on the HUD when the car is at a standstill."),
|
||||
"../assets/offroad/icon_monitoring.png",
|
||||
"",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"RoadNameToggle",
|
||||
tr("Display Road Name"),
|
||||
tr("Displays the name of the road the car is traveling on. The OpenStreetMap database of the location must be downloaded from the OSM panel to fetch the road name."),
|
||||
"",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"GreenLightAlert",
|
||||
tr("Green Traffic Light Alert (Beta)"),
|
||||
QString("%1<br>"
|
||||
"<h4>%2</h4><br>")
|
||||
.arg(tr("A chime and on-screen alert will play when the traffic light you are waiting for turns green and you have no vehicle in front of you."))
|
||||
.arg(tr("Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly.")),
|
||||
"",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"LeadDepartAlert",
|
||||
tr("Lead Departure Alert (Beta)"),
|
||||
QString("%1<br>"
|
||||
"<h4>%2</h4><br>")
|
||||
.arg(tr("A chime and on-screen alert will play when you are stopped, and the vehicle in front of you start moving."))
|
||||
.arg(tr("Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly.")),
|
||||
"",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"TrueVEgoUI",
|
||||
tr("Speedometer: Always Display True Speed"),
|
||||
tr("Always display the true vehicle current speed from wheel speed sensors."),
|
||||
"",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"HideVEgoUI",
|
||||
tr("Speedometer: Hide from Onroad Screen"),
|
||||
tr("When enabled, the speedometer on the onroad screen is not displayed."),
|
||||
"",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"ShowTurnSignals",
|
||||
tr("Display Turn Signals"),
|
||||
tr("When enabled, visual turn indicators are drawn on the HUD."),
|
||||
"",
|
||||
false,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* 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/onroad/alerts.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <map>
|
||||
#include <QRect>
|
||||
#include <QFont>
|
||||
|
||||
OnroadAlerts::Alert OnroadAlertsSP::getAlert(const SubMaster &sm, uint64_t started_frame) {
|
||||
OnroadAlerts::Alert alert = OnroadAlerts::getAlert(sm, started_frame);
|
||||
alert.text1.replace("openpilot", "sunnypilot");
|
||||
alert.text2.replace("openpilot", "sunnypilot");
|
||||
return alert;
|
||||
}
|
||||
|
||||
void OnroadAlertsSP::paintEvent(QPaintEvent *event) {
|
||||
if (alert.size == cereal::SelfdriveState::AlertSize::NONE) {
|
||||
return;
|
||||
} else if (alert.size == cereal::SelfdriveState::AlertSize::FULL) {
|
||||
OnroadAlerts::paintEvent(event);
|
||||
return;
|
||||
}
|
||||
static std::map<cereal::SelfdriveState::AlertSize, const int> alert_heights = {
|
||||
{cereal::SelfdriveState::AlertSize::SMALL, 271},
|
||||
{cereal::SelfdriveState::AlertSize::MID, 420}
|
||||
};
|
||||
int h = alert_heights[alert.size];
|
||||
|
||||
QPainter p(this);
|
||||
QFont topFont;
|
||||
QFont bottomFont;
|
||||
QRect topTextBoundingRect;
|
||||
QRect bottomTextBoundingRect;
|
||||
QRect rect;
|
||||
|
||||
int margin = 40;
|
||||
int radius = 30;
|
||||
|
||||
const int dev_ui_info = uiStateSP()->scene.dev_ui_info;
|
||||
const int v_adjustment = dev_ui_info > 1 && alert.size != cereal::SelfdriveState::AlertSize::FULL ? 40 : 0;
|
||||
const int h_adjustment = dev_ui_info > 0 && alert.size != cereal::SelfdriveState::AlertSize::FULL ? 230 : 0;
|
||||
|
||||
if (alert.size == cereal::SelfdriveState::AlertSize::SMALL) {
|
||||
topFont = InterFont(74, QFont::DemiBold);
|
||||
QFontMetrics fmTop(topFont);
|
||||
topTextBoundingRect = fmTop.boundingRect(
|
||||
QRect(0 + margin, height() - h + margin - v_adjustment, width() - margin * 2 - h_adjustment, 0), Qt::TextWordWrap,
|
||||
alert.text1);
|
||||
h = topTextBoundingRect.height();
|
||||
rect = QRect(0 + margin, height() - h - margin * 2 - v_adjustment, width() - margin * 2 - h_adjustment, h + margin);
|
||||
} else if (alert.size == cereal::SelfdriveState::AlertSize::MID) {
|
||||
topFont = InterFont(88, QFont::Bold);
|
||||
bottomFont = InterFont(66);
|
||||
QFontMetrics fmTop(topFont);
|
||||
QFontMetrics fmBotton(bottomFont);
|
||||
topTextBoundingRect = fmTop.boundingRect(
|
||||
QRect(0 + margin, height() - h + margin - v_adjustment, width() - margin * 2 - h_adjustment, 0), Qt::TextWordWrap,
|
||||
alert.text1);
|
||||
bottomTextBoundingRect = fmBotton.boundingRect(
|
||||
QRect(0 + margin, height() - h + margin - v_adjustment + topTextBoundingRect.height(),
|
||||
width() - margin * 2 - h_adjustment, 0), Qt::TextWordWrap, alert.text2);
|
||||
h = topTextBoundingRect.height() + bottomTextBoundingRect.height() + margin * 2;
|
||||
rect = QRect(0 + margin, height() - h - margin * 2 - v_adjustment, width() - margin * 2 - h_adjustment, h + margin);
|
||||
}
|
||||
|
||||
|
||||
// draw background + gradient
|
||||
// draw background + gradient
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
|
||||
p.setBrush(QBrush(alert_colors[alert.status]));
|
||||
p.drawRoundedRect(rect, radius, radius);
|
||||
|
||||
QLinearGradient g(0, rect.y(), 0, rect.bottom());
|
||||
g.setColorAt(0, QColor::fromRgbF(0, 0, 0, 0.05));
|
||||
g.setColorAt(1, QColor::fromRgbF(0, 0, 0, 0.35));
|
||||
|
||||
p.setCompositionMode(QPainter::CompositionMode_DestinationOver);
|
||||
p.setBrush(QBrush(g));
|
||||
p.drawRoundedRect(rect, radius, radius);
|
||||
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
|
||||
|
||||
// text
|
||||
p.setPen(QColor(0xff, 0xff, 0xff));
|
||||
p.setRenderHint(QPainter::TextAntialiasing);
|
||||
p.setFont(topFont);
|
||||
if (alert.size == cereal::SelfdriveState::AlertSize::SMALL) {
|
||||
p.drawText(rect, Qt::AlignCenter | Qt::TextWordWrap, alert.text1);
|
||||
} else if (alert.size == cereal::SelfdriveState::AlertSize::MID) {
|
||||
QRect topText = QRect(rect.x(), rect.top() + margin, rect.width(), topTextBoundingRect.height());
|
||||
p.drawText(topText, Qt::AlignHCenter | Qt::AlignTop | Qt::TextWordWrap | Qt::AlignCenter, alert.text1);
|
||||
p.setFont(bottomFont);
|
||||
p.drawText(QRect(rect.x(), topText.bottom() + margin, rect.width(), bottomTextBoundingRect.height()),
|
||||
Qt::AlignHCenter | Qt::TextWordWrap | Qt::AlignCenter, alert.text2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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/onroad/alerts.h"
|
||||
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||
|
||||
class OnroadAlertsSP : public OnroadAlerts {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
OnroadAlertsSP(QWidget *parent = 0) : OnroadAlerts(parent) {}
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *) override;
|
||||
Alert getAlert(const SubMaster &sm, uint64_t started_frame);
|
||||
};
|
||||
@@ -11,13 +11,22 @@
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
|
||||
|
||||
HudRendererSP::HudRendererSP() {}
|
||||
HudRendererSP::HudRendererSP() {
|
||||
plus_arrow_up_img = loadPixmap("../../sunnypilot/selfdrive/assets/img_plus_arrow_up", {105, 105});
|
||||
minus_arrow_down_img = loadPixmap("../../sunnypilot/selfdrive/assets/img_minus_arrow_down", {105, 105});
|
||||
|
||||
int small_max = e2e_alert_small * 2 - 40;
|
||||
int large_max = e2e_alert_large * 2 - 40;
|
||||
green_light_alert_small_img = loadPixmap("../../sunnypilot/selfdrive/assets/images/green_light.png", {small_max, small_max});
|
||||
green_light_alert_large_img = loadPixmap("../../sunnypilot/selfdrive/assets/images/green_light.png", {large_max, large_max});
|
||||
lead_depart_alert_small_img = loadPixmap("../../sunnypilot/selfdrive/assets/images/lead_depart.png", {small_max, small_max});
|
||||
lead_depart_alert_large_img = loadPixmap("../../sunnypilot/selfdrive/assets/images/lead_depart.png", {large_max, large_max});
|
||||
}
|
||||
|
||||
void HudRendererSP::updateState(const UIState &s) {
|
||||
HudRenderer::updateState(s);
|
||||
|
||||
const SubMaster &sm = *(s.sm);
|
||||
const bool cs_alive = sm.alive("controlsState");
|
||||
const auto cs = sm["controlsState"].getControlsState();
|
||||
const auto car_state = sm["carState"].getCarState();
|
||||
const auto car_control = sm["carControl"].getCarControl();
|
||||
@@ -27,6 +36,31 @@ void HudRendererSP::updateState(const UIState &s) {
|
||||
const auto ltp = sm["liveTorqueParameters"].getLiveTorqueParameters();
|
||||
const auto car_params = sm["carParams"].getCarParams();
|
||||
const auto lp_sp = sm["longitudinalPlanSP"].getLongitudinalPlanSP();
|
||||
const auto lmd = sm["liveMapDataSP"].getLiveMapDataSP();
|
||||
|
||||
float speedConv = is_metric ? MS_TO_KPH : MS_TO_MPH;
|
||||
speedLimit = lp_sp.getSpeedLimit().getResolver().getSpeedLimit() * speedConv;
|
||||
speedLimitLast = lp_sp.getSpeedLimit().getResolver().getSpeedLimitLast() * speedConv;
|
||||
speedLimitOffset = lp_sp.getSpeedLimit().getResolver().getSpeedLimitOffset() * speedConv;
|
||||
speedLimitValid = lp_sp.getSpeedLimit().getResolver().getSpeedLimitValid();
|
||||
speedLimitLastValid = lp_sp.getSpeedLimit().getResolver().getSpeedLimitLastValid();
|
||||
speedLimitFinalLast = lp_sp.getSpeedLimit().getResolver().getSpeedLimitFinalLast() * speedConv;
|
||||
speedLimitMode = static_cast<SpeedLimitMode>(s.scene.speed_limit_mode);
|
||||
speedLimitAssistState = lp_sp.getSpeedLimit().getAssist().getState();
|
||||
speedLimitAssistActive = lp_sp.getSpeedLimit().getAssist().getActive();
|
||||
roadName = s.scene.road_name;
|
||||
if (sm.updated("liveMapDataSP")) {
|
||||
roadNameStr = QString::fromStdString(lmd.getRoadName());
|
||||
speedLimitAheadValid = lmd.getSpeedLimitAheadValid();
|
||||
speedLimitAhead = lmd.getSpeedLimitAhead() * speedConv;
|
||||
speedLimitAheadDistance = lmd.getSpeedLimitAheadDistance();
|
||||
if (speedLimitAheadDistance < speedLimitAheadDistancePrev && speedLimitAheadValidFrame < SPEED_LIMIT_AHEAD_VALID_FRAME_THRESHOLD) {
|
||||
speedLimitAheadValidFrame++;
|
||||
} else if (speedLimitAheadDistance > speedLimitAheadDistancePrev && speedLimitAheadValidFrame > 0) {
|
||||
speedLimitAheadValidFrame--;
|
||||
}
|
||||
}
|
||||
speedLimitAheadDistancePrev = speedLimitAheadDistance;
|
||||
|
||||
static int reverse_delay = 0;
|
||||
bool reverse_allowed = false;
|
||||
@@ -41,13 +75,6 @@ void HudRendererSP::updateState(const UIState &s) {
|
||||
}
|
||||
|
||||
reversing = reverse_allowed;
|
||||
is_metric = s.scene.is_metric;
|
||||
|
||||
// Handle older routes where vEgoCluster is not set
|
||||
v_ego_cluster_seen = v_ego_cluster_seen || car_state.getVEgoCluster() != 0.0;
|
||||
float v_ego = v_ego_cluster_seen ? car_state.getVEgoCluster() : car_state.getVEgo();
|
||||
speed = cs_alive ? std::max<float>(0.0, v_ego) : 0.0;
|
||||
speed *= is_metric ? MS_TO_KPH : MS_TO_MPH;
|
||||
|
||||
latActive = car_control.getLatActive();
|
||||
steerOverride = car_state.getSteeringPressed();
|
||||
@@ -83,26 +110,65 @@ void HudRendererSP::updateState(const UIState &s) {
|
||||
longOverride = car_control.getCruiseControl().getOverride();
|
||||
smartCruiseControlVisionEnabled = lp_sp.getSmartCruiseControl().getVision().getEnabled();
|
||||
smartCruiseControlVisionActive = lp_sp.getSmartCruiseControl().getVision().getActive();
|
||||
smartCruiseControlMapEnabled = lp_sp.getSmartCruiseControl().getMap().getEnabled();
|
||||
smartCruiseControlMapActive = lp_sp.getSmartCruiseControl().getMap().getActive();
|
||||
|
||||
greenLightAlert = lp_sp.getE2eAlerts().getGreenLightAlert();
|
||||
leadDepartAlert = lp_sp.getE2eAlerts().getLeadDepartAlert();
|
||||
|
||||
// override stock current speed values
|
||||
float v_ego = (v_ego_cluster_seen && !s.scene.trueVEgoUI) ? car_state.getVEgoCluster() : car_state.getVEgo();
|
||||
speed = std::max<float>(0.0f, v_ego * (is_metric ? MS_TO_KPH : MS_TO_MPH));
|
||||
hideVEgoUI = s.scene.hideVEgoUI;
|
||||
|
||||
leftBlinkerOn = car_state.getLeftBlinker();
|
||||
rightBlinkerOn = car_state.getRightBlinker();
|
||||
leftBlindspot = car_state.getLeftBlindspot();
|
||||
rightBlindspot = car_state.getRightBlindspot();
|
||||
showTurnSignals = s.scene.turn_signals;
|
||||
}
|
||||
|
||||
void HudRendererSP::draw(QPainter &p, const QRect &surface_rect) {
|
||||
HudRenderer::draw(p, surface_rect);
|
||||
|
||||
e2eAlertDisplayTimer = std::max(0, e2eAlertDisplayTimer - 1);
|
||||
|
||||
p.save();
|
||||
|
||||
if (is_cruise_available) {
|
||||
drawSetSpeedSP(p, surface_rect);
|
||||
}
|
||||
|
||||
if (!hideVEgoUI) {
|
||||
drawCurrentSpeedSP(p, surface_rect);
|
||||
}
|
||||
|
||||
if (!reversing) {
|
||||
// Smart Cruise Control
|
||||
int x_offset = -260;
|
||||
int y1_offset = -80;
|
||||
// int y2_offset = -140; // reserved for 2 icons
|
||||
int y2_offset = -140;
|
||||
|
||||
int y_scc_v = 0, y_scc_m = 0;
|
||||
const int orders[2] = {y1_offset, y2_offset};
|
||||
int i = 0;
|
||||
// SCC-V takes first order
|
||||
if (smartCruiseControlVisionEnabled) y_scc_v = orders[i++];
|
||||
if (smartCruiseControlMapEnabled) y_scc_m = orders[i++];
|
||||
|
||||
// Smart Cruise Control - Vision
|
||||
bool scc_vision_active_pulse = pulseElement(smartCruiseControlVisionFrame);
|
||||
if ((smartCruiseControlVisionEnabled && !smartCruiseControlVisionActive) || (smartCruiseControlVisionActive && scc_vision_active_pulse)) {
|
||||
drawSmartCruiseControlOnroadIcon(p, surface_rect, x_offset, y1_offset, "SCC-V");
|
||||
drawSmartCruiseControlOnroadIcon(p, surface_rect, x_offset, y_scc_v, "SCC-V");
|
||||
}
|
||||
smartCruiseControlVisionFrame = smartCruiseControlVisionActive ? (smartCruiseControlVisionFrame + 1) : 0;
|
||||
|
||||
if (smartCruiseControlVisionActive) {
|
||||
smartCruiseControlVisionFrame++;
|
||||
} else {
|
||||
smartCruiseControlVisionFrame = 0;
|
||||
// Smart Cruise Control - Map
|
||||
bool scc_map_active_pulse = pulseElement(smartCruiseControlMapFrame);
|
||||
if ((smartCruiseControlMapEnabled && !smartCruiseControlMapActive) || (smartCruiseControlMapActive && scc_map_active_pulse)) {
|
||||
drawSmartCruiseControlOnroadIcon(p, surface_rect, x_offset, y_scc_m, "SCC-M");
|
||||
}
|
||||
smartCruiseControlMapFrame = smartCruiseControlMapActive ? (smartCruiseControlMapFrame + 1) : 0;
|
||||
|
||||
// Bottom Dev UI
|
||||
if (devUiInfo == 2) {
|
||||
@@ -119,11 +185,80 @@ void HudRendererSP::draw(QPainter &p, const QRect &surface_rect) {
|
||||
drawRightDevUI(p, surface_rect.right() - 184 - UI_BORDER_SIZE * 2, UI_BORDER_SIZE * 2 + rect_right.height());
|
||||
}
|
||||
|
||||
// Speed Limit
|
||||
bool showSpeedLimit;
|
||||
bool speed_limit_assist_pre_active_pulse = pulseElement(speedLimitAssistFrame);
|
||||
|
||||
// Position speed limit sign next to set speed box
|
||||
const int sign_width = is_metric ? 200 : 172;
|
||||
const int sign_x = is_metric ? 280 : 272;
|
||||
const int sign_y = 45;
|
||||
const int sign_height = 204;
|
||||
QRect sign_rect(sign_x, sign_y, sign_width, sign_height);
|
||||
|
||||
if (speedLimitAssistState == cereal::LongitudinalPlanSP::SpeedLimit::AssistState::PRE_ACTIVE) {
|
||||
speedLimitAssistFrame++;
|
||||
showSpeedLimit = speed_limit_assist_pre_active_pulse;
|
||||
drawSpeedLimitPreActiveArrow(p, sign_rect);
|
||||
} else {
|
||||
speedLimitAssistFrame = 0;
|
||||
showSpeedLimit = speedLimitMode != SpeedLimitMode::OFF;
|
||||
}
|
||||
|
||||
if (showSpeedLimit) {
|
||||
drawSpeedLimitSigns(p, sign_rect);
|
||||
|
||||
// do not show during SLA's preActive state
|
||||
if (speedLimitAssistState != cereal::LongitudinalPlanSP::SpeedLimit::AssistState::PRE_ACTIVE) {
|
||||
drawUpcomingSpeedLimit(p);
|
||||
}
|
||||
}
|
||||
|
||||
// Road Name
|
||||
drawRoadName(p, surface_rect);
|
||||
|
||||
// Green Light & Lead Depart Alerts
|
||||
if (greenLightAlert or leadDepartAlert) {
|
||||
e2eAlertDisplayTimer = 3 * UI_FREQ;
|
||||
// reset onroad sleep timer for e2e alerts
|
||||
uiStateSP()->reset_onroad_sleep_timer();
|
||||
}
|
||||
|
||||
if (e2eAlertDisplayTimer > 0) {
|
||||
e2eAlertFrame++;
|
||||
if (greenLightAlert) {
|
||||
alert_text = tr("GREEN\nLIGHT");
|
||||
alert_img = devUiInfo > 0 ? green_light_alert_small_img : green_light_alert_large_img;
|
||||
}
|
||||
else if (leadDepartAlert) {
|
||||
alert_text = tr("LEAD VEHICLE\nDEPARTING");
|
||||
alert_img = devUiInfo > 0 ? lead_depart_alert_small_img : lead_depart_alert_large_img;
|
||||
}
|
||||
drawE2eAlert(p, surface_rect);
|
||||
}
|
||||
// Standstill Timer
|
||||
if (standstillTimer) {
|
||||
drawStandstillTimer(p, surface_rect.right() / 12 * 10, surface_rect.bottom() / 12 * 1.53);
|
||||
else if (standstillTimer && isStandstill) {
|
||||
alert_img = QPixmap();
|
||||
|
||||
standstillElapsedTime += 1.0 / UI_FREQ;
|
||||
int minute = static_cast<int>(standstillElapsedTime / 60);
|
||||
int second = static_cast<int>(standstillElapsedTime - (minute * 60));
|
||||
alert_text = QString("%1:%2").arg(minute, 1, 10, QChar('0')).arg(second, 2, 10, QChar('0'));
|
||||
drawE2eAlert(p, surface_rect, tr("STOPPED"));
|
||||
e2eAlertFrame++;
|
||||
}
|
||||
// No Alerts displayed
|
||||
else {
|
||||
e2eAlertFrame = 0;
|
||||
}
|
||||
|
||||
// Blinker
|
||||
if (showTurnSignals) {
|
||||
drawBlinker(p, surface_rect);
|
||||
}
|
||||
}
|
||||
|
||||
p.restore();
|
||||
}
|
||||
|
||||
void HudRendererSP::drawText(QPainter &p, int x, int y, const QString &text, QColor color) {
|
||||
@@ -278,36 +413,419 @@ void HudRendererSP::drawBottomDevUI(QPainter &p, int x, int y) {
|
||||
rw += drawBottomDevUIElement(p, rw, y, altitudeElement.value, altitudeElement.label, altitudeElement.units, altitudeElement.color);
|
||||
}
|
||||
|
||||
void HudRendererSP::drawStandstillTimer(QPainter &p, int x, int y) {
|
||||
if (isStandstill) {
|
||||
standstillElapsedTime += 1.0 / UI_FREQ;
|
||||
void HudRendererSP::drawSpeedLimitSigns(QPainter &p, QRect &sign_rect) {
|
||||
bool speedLimitWarningEnabled = speedLimitMode >= SpeedLimitMode::WARNING; // TODO-SP: update to include SpeedLimitMode::ASSIST
|
||||
bool hasSpeedLimit = speedLimitValid || speedLimitLastValid;
|
||||
bool overspeed = hasSpeedLimit && std::nearbyint(speedLimitFinalLast) < std::nearbyint(speed);
|
||||
QString speedLimitStr = hasSpeedLimit ? QString::number(std::nearbyint(speedLimitLast)) : "---";
|
||||
|
||||
int minute = static_cast<int>(standstillElapsedTime / 60);
|
||||
int second = static_cast<int>(standstillElapsedTime - (minute * 60));
|
||||
// Offset display text
|
||||
QString speedLimitSubText = "";
|
||||
if (speedLimitOffset != 0) {
|
||||
speedLimitSubText = (speedLimitOffset > 0 ? "" : "-") + QString::number(std::nearbyint(speedLimitOffset));
|
||||
}
|
||||
|
||||
// stop sign for standstill timer
|
||||
const int size = 190; // size
|
||||
const float angle = M_PI / 8.0;
|
||||
float speedLimitSubTextFactor = is_metric ? 0.5 : 0.6;
|
||||
if (speedLimitSubText.size() >= 3) {
|
||||
speedLimitSubTextFactor = 0.475;
|
||||
}
|
||||
|
||||
QPolygon octagon;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
float curr_angle = angle + i * M_PI / 4.0;
|
||||
int point_x = x + size / 2 * cos(curr_angle);
|
||||
int point_y = y + size / 2 * sin(curr_angle);
|
||||
octagon << QPoint(point_x, point_y);
|
||||
int alpha = 255;
|
||||
QColor red_color = QColor(255, 0, 0, alpha);
|
||||
QColor speed_color = (speedLimitWarningEnabled && overspeed) ? red_color :
|
||||
(!speedLimitValid && speedLimitLastValid ? QColor(0x91, 0x9b, 0x95, 0xf1) : QColor(0, 0, 0, alpha));
|
||||
|
||||
if (is_metric) {
|
||||
// EU Vienna Convention style circular sign
|
||||
QRect vienna_rect = sign_rect;
|
||||
int circle_size = std::min(vienna_rect.width(), vienna_rect.height());
|
||||
QRect circle_rect(vienna_rect.x(), vienna_rect.y(), circle_size, circle_size);
|
||||
|
||||
if (vienna_rect.width() > vienna_rect.height()) {
|
||||
circle_rect.moveLeft(vienna_rect.x() + (vienna_rect.width() - circle_size) / 2);
|
||||
} else if (vienna_rect.height() > vienna_rect.width()) {
|
||||
circle_rect.moveTop(vienna_rect.y() + (vienna_rect.height() - circle_size) / 2);
|
||||
}
|
||||
|
||||
p.setPen(QPen(Qt::white, 6));
|
||||
p.setBrush(QColor(255, 90, 81, 200)); // red pastel
|
||||
p.drawPolygon(octagon);
|
||||
// White background circle
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(QColor(255, 255, 255, alpha));
|
||||
p.drawEllipse(circle_rect);
|
||||
|
||||
QString time_str = QString("%1:%2").arg(minute, 1, 10, QChar('0')).arg(second, 2, 10, QChar('0'));
|
||||
p.setFont(InterFont(55, QFont::Bold));
|
||||
p.setPen(Qt::white);
|
||||
QRect timerTextRect = p.fontMetrics().boundingRect(QString(time_str));
|
||||
timerTextRect.moveCenter({x, y});
|
||||
p.drawText(timerTextRect, Qt::AlignCenter, QString(time_str));
|
||||
// Red border ring with color coding
|
||||
QRect red_ring = circle_rect;
|
||||
|
||||
p.setBrush(red_color);
|
||||
p.drawEllipse(red_ring);
|
||||
|
||||
// Center white circle for text
|
||||
int ring_size = circle_size * 0.12;
|
||||
QRect center_circle = red_ring.adjusted(ring_size, ring_size, -ring_size, -ring_size);
|
||||
p.setBrush(QColor(255, 255, 255, alpha));
|
||||
p.drawEllipse(center_circle);
|
||||
|
||||
// Speed value, smaller font for 3+ digits
|
||||
int font_size = (speedLimitStr.size() >= 3) ? 70 : 85;
|
||||
p.setFont(InterFont(font_size, QFont::Bold));
|
||||
|
||||
p.setPen(speed_color);
|
||||
p.drawText(center_circle, Qt::AlignCenter, speedLimitStr);
|
||||
|
||||
// Offset value in small circular box
|
||||
if (!speedLimitSubText.isEmpty() && hasSpeedLimit) {
|
||||
int offset_circle_size = circle_size * 0.4;
|
||||
int overlap = offset_circle_size * 0.25;
|
||||
QRect offset_circle_rect(
|
||||
circle_rect.right() - offset_circle_size/1.25 + overlap,
|
||||
circle_rect.top() - offset_circle_size/1.75 + overlap,
|
||||
offset_circle_size,
|
||||
offset_circle_size
|
||||
);
|
||||
|
||||
p.setPen(QPen(QColor(77, 77, 77, 255), 6));
|
||||
p.setBrush(QColor(0, 0, 0, alpha));
|
||||
p.drawEllipse(offset_circle_rect);
|
||||
|
||||
p.setFont(InterFont(offset_circle_size * speedLimitSubTextFactor, QFont::Bold));
|
||||
p.setPen(QColor(255, 255, 255, alpha));
|
||||
p.drawText(offset_circle_rect, Qt::AlignCenter, speedLimitSubText);
|
||||
}
|
||||
} else {
|
||||
standstillElapsedTime = 0.0;
|
||||
// US/Canada MUTCD style sign
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(QColor(255, 255, 255, alpha));
|
||||
p.drawRoundedRect(sign_rect, 32, 32);
|
||||
|
||||
// Inner border with violation color coding
|
||||
QRect inner_rect = sign_rect.adjusted(10, 10, -10, -10);
|
||||
QColor border_color = QColor(0, 0, 0, alpha);
|
||||
|
||||
p.setPen(QPen(border_color, 4));
|
||||
p.setBrush(QColor(255, 255, 255, alpha));
|
||||
p.drawRoundedRect(inner_rect, 22, 22);
|
||||
|
||||
// "SPEED LIMIT" text
|
||||
p.setFont(InterFont(40, QFont::DemiBold));
|
||||
p.setPen(QColor(0, 0, 0, alpha));
|
||||
p.drawText(inner_rect.adjusted(0, 10, 0, 0), Qt::AlignTop | Qt::AlignHCenter, tr("SPEED"));
|
||||
p.drawText(inner_rect.adjusted(0, 50, 0, 0), Qt::AlignTop | Qt::AlignHCenter, tr("LIMIT"));
|
||||
|
||||
// Speed value with color coding
|
||||
p.setFont(InterFont(90, QFont::Bold));
|
||||
|
||||
p.setPen(speed_color);
|
||||
p.drawText(inner_rect.adjusted(0, 80, 0, 0), Qt::AlignTop | Qt::AlignHCenter, speedLimitStr);
|
||||
|
||||
// Offset value in small box
|
||||
if (!speedLimitSubText.isEmpty() && hasSpeedLimit) {
|
||||
int offset_box_size = sign_rect.width() * 0.4;
|
||||
int overlap = offset_box_size * 0.25;
|
||||
QRect offset_box_rect(
|
||||
sign_rect.right() - offset_box_size/1.5 + overlap,
|
||||
sign_rect.top() - offset_box_size/1.25 + overlap,
|
||||
offset_box_size,
|
||||
offset_box_size
|
||||
);
|
||||
|
||||
int corner_radius = offset_box_size * 0.2;
|
||||
p.setPen(QPen(QColor(77, 77, 77, 255), 6));
|
||||
p.setBrush(QColor(0, 0, 0, alpha));
|
||||
p.drawRoundedRect(offset_box_rect, corner_radius, corner_radius);
|
||||
|
||||
p.setFont(InterFont(offset_box_size * speedLimitSubTextFactor, QFont::Bold));
|
||||
p.setPen(QColor(255, 255, 255, alpha));
|
||||
p.drawText(offset_box_rect, Qt::AlignCenter, speedLimitSubText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HudRendererSP::drawUpcomingSpeedLimit(QPainter &p) {
|
||||
bool speed_limit_ahead = speedLimitAheadValid && speedLimitAhead > 0 && speedLimitAhead != speedLimit && speedLimitAheadValidFrame > 0;
|
||||
if (!speed_limit_ahead) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto roundToInterval = [&](float distance, int interval, int threshold) {
|
||||
int base = static_cast<int>(distance / interval) * interval;
|
||||
return (distance - base >= threshold) ? base + interval : base;
|
||||
};
|
||||
|
||||
auto outputDistance = [&] {
|
||||
if (is_metric) {
|
||||
if (speedLimitAheadDistance < 50) return tr("Near");
|
||||
if (speedLimitAheadDistance >= 1000) return QString::number(speedLimitAheadDistance * METER_TO_KM, 'f', 1) + tr("km");
|
||||
|
||||
int rounded = (speedLimitAheadDistance < 200) ? std::max(10, roundToInterval(speedLimitAheadDistance, 10, 5)) : roundToInterval(speedLimitAheadDistance, 100, 50);
|
||||
return QString::number(rounded) + tr("m");
|
||||
} else {
|
||||
float distance_ft = speedLimitAheadDistance * METER_TO_FOOT;
|
||||
if (distance_ft < 100) return tr("Near");
|
||||
if (distance_ft >= 900) return QString::number(speedLimitAheadDistance * METER_TO_MILE, 'f', 1) + tr("mi");
|
||||
|
||||
int rounded = (distance_ft < 500) ? std::max(50, roundToInterval(distance_ft, 50, 25)) : roundToInterval(distance_ft, 100, 50);
|
||||
return QString::number(rounded) + tr("ft");
|
||||
}
|
||||
};
|
||||
|
||||
QString speedStr = QString::number(std::nearbyint(speedLimitAhead));
|
||||
QString distanceStr = outputDistance();
|
||||
|
||||
// Position below current speed limit sign
|
||||
const int sign_width = is_metric ? 200 : 172;
|
||||
const int sign_x = is_metric ? 280 : 272;
|
||||
const int sign_y = 45;
|
||||
const int sign_height = 204;
|
||||
|
||||
const int ahead_width = 170;
|
||||
const int ahead_height = 160;
|
||||
const int ahead_x = sign_x + (sign_width - ahead_width) / 2;
|
||||
const int ahead_y = sign_y + sign_height + 10;
|
||||
|
||||
QRect ahead_rect(ahead_x, ahead_y, ahead_width, ahead_height);
|
||||
p.setPen(QPen(QColor(255, 255, 255, 100), 3));
|
||||
p.setBrush(QColor(0, 0, 0, 180));
|
||||
p.drawRoundedRect(ahead_rect, 16, 16);
|
||||
|
||||
// "AHEAD" label
|
||||
p.setFont(InterFont(40, QFont::DemiBold));
|
||||
p.setPen(QColor(200, 200, 200, 255));
|
||||
p.drawText(ahead_rect.adjusted(0, 4, 0, 0), Qt::AlignTop | Qt::AlignHCenter, tr("AHEAD"));
|
||||
|
||||
// Speed value
|
||||
p.setFont(InterFont(70, QFont::Bold));
|
||||
p.setPen(QColor(255, 255, 255, 255));
|
||||
p.drawText(ahead_rect.adjusted(0, 38, 0, 0), Qt::AlignTop | Qt::AlignHCenter, speedStr);
|
||||
|
||||
// Distance
|
||||
p.setFont(InterFont(40, QFont::Normal));
|
||||
p.setPen(QColor(180, 180, 180, 255));
|
||||
p.drawText(ahead_rect.adjusted(0, 110, 0, 0), Qt::AlignTop | Qt::AlignHCenter, distanceStr);
|
||||
}
|
||||
|
||||
void HudRendererSP::drawRoadName(QPainter &p, const QRect &surface_rect) {
|
||||
if (!roadName || roadNameStr.isEmpty()) return;
|
||||
|
||||
// Measure text to size container
|
||||
p.setFont(InterFont(46, QFont::DemiBold));
|
||||
QFontMetrics fm(p.font());
|
||||
|
||||
int text_width = fm.horizontalAdvance(roadNameStr);
|
||||
int padding = 40;
|
||||
int rect_width = text_width + padding;
|
||||
|
||||
// Constrain to reasonable bounds
|
||||
int min_width = 200;
|
||||
int max_width = surface_rect.width() - 40;
|
||||
rect_width = std::max(min_width, std::min(rect_width, max_width));
|
||||
|
||||
// Center at top of screen
|
||||
QRect road_rect(surface_rect.width() / 2 - rect_width / 2, -4, rect_width, 60);
|
||||
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(QColor(0, 0, 0, 120));
|
||||
p.drawRoundedRect(road_rect, 12, 12);
|
||||
|
||||
p.setPen(QColor(255, 255, 255, 200));
|
||||
|
||||
// Truncate if still too long
|
||||
QString truncated = fm.elidedText(roadNameStr, Qt::ElideRight, road_rect.width() - 20);
|
||||
p.drawText(road_rect, Qt::AlignCenter, truncated);
|
||||
}
|
||||
|
||||
void HudRendererSP::drawSpeedLimitPreActiveArrow(QPainter &p, QRect &sign_rect) {
|
||||
const int sign_margin = 12;
|
||||
const int arrow_spacing = sign_margin * 3;
|
||||
int arrow_x = sign_rect.right() + arrow_spacing;
|
||||
|
||||
int _set_speed = std::nearbyint(set_speed);
|
||||
int _speed_limit_final_last = std::nearbyint(speedLimitFinalLast);
|
||||
|
||||
// Calculate the vertical offset using a sinusoidal function for smooth bouncing
|
||||
double bounce_frequency = 2.0 * M_PI / UI_FREQ; // 20 frames for one full oscillation
|
||||
int bounce_offset = 20 * sin(speedLimitAssistFrame * bounce_frequency); // Adjust the amplitude (20 pixels) as needed
|
||||
|
||||
if (_set_speed < _speed_limit_final_last) {
|
||||
QPoint iconPosition(arrow_x, sign_rect.center().y() - plus_arrow_up_img.height() / 2 + bounce_offset);
|
||||
p.drawPixmap(iconPosition, plus_arrow_up_img);
|
||||
} else if (_set_speed > _speed_limit_final_last) {
|
||||
QPoint iconPosition(arrow_x, sign_rect.center().y() - minus_arrow_down_img.height() / 2 - bounce_offset);
|
||||
p.drawPixmap(iconPosition, minus_arrow_down_img);
|
||||
}
|
||||
}
|
||||
|
||||
void HudRendererSP::drawSetSpeedSP(QPainter &p, const QRect &surface_rect) {
|
||||
// Draw outer box + border to contain set speed
|
||||
const QSize default_size = {172, 204};
|
||||
QSize set_speed_size = is_metric ? QSize(200, 204) : default_size;
|
||||
QRect set_speed_rect(QPoint(60 + (default_size.width() - set_speed_size.width()) / 2, 45), set_speed_size);
|
||||
|
||||
// Draw set speed box
|
||||
p.setPen(QPen(QColor(255, 255, 255, 75), 6));
|
||||
p.setBrush(QColor(0, 0, 0, 166));
|
||||
p.drawRoundedRect(set_speed_rect, 32, 32);
|
||||
|
||||
// Colors based on status
|
||||
QColor max_color = QColor(0xa6, 0xa6, 0xa6, 0xff);
|
||||
QColor set_speed_color = QColor(0x72, 0x72, 0x72, 0xff);
|
||||
if (is_cruise_set) {
|
||||
set_speed_color = QColor(255, 255, 255);
|
||||
if (speedLimitAssistActive) {
|
||||
set_speed_color = longOverride ? QColor(0x91, 0x9b, 0x95, 0xff) : QColor(0, 0xff, 0, 0xff);
|
||||
max_color = longOverride ? QColor(0x91, 0x9b, 0x95, 0xff) : QColor(0x80, 0xd8, 0xa6, 0xff);
|
||||
} else {
|
||||
if (status == STATUS_DISENGAGED) {
|
||||
max_color = QColor(255, 255, 255);
|
||||
} else if (status == STATUS_OVERRIDE) {
|
||||
max_color = QColor(0x91, 0x9b, 0x95, 0xff);
|
||||
} else {
|
||||
max_color = QColor(0x80, 0xd8, 0xa6, 0xff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw "MAX" text
|
||||
p.setFont(InterFont(40, QFont::DemiBold));
|
||||
p.setPen(max_color);
|
||||
p.drawText(set_speed_rect.adjusted(0, 27, 0, 0), Qt::AlignTop | Qt::AlignHCenter, tr("MAX"));
|
||||
|
||||
// Draw set speed
|
||||
QString setSpeedStr = is_cruise_set ? QString::number(std::nearbyint(set_speed)) : "–";
|
||||
p.setFont(InterFont(90, QFont::Bold));
|
||||
p.setPen(set_speed_color);
|
||||
p.drawText(set_speed_rect.adjusted(0, 77, 0, 0), Qt::AlignTop | Qt::AlignHCenter, setSpeedStr);
|
||||
}
|
||||
|
||||
void HudRendererSP::drawE2eAlert(QPainter &p, const QRect &surface_rect, const QString &alert_alt_text) {
|
||||
int size = devUiInfo > 0 ? e2e_alert_small : e2e_alert_large;
|
||||
int x = surface_rect.center().x() + surface_rect.width() / 4;
|
||||
int y = surface_rect.center().y() + 40;
|
||||
x += devUiInfo > 0 ? 0 : 50;
|
||||
y += devUiInfo > 0 ? 0 : 80;
|
||||
QRect alertRect(x - size, y - size, size * 2, size * 2);
|
||||
|
||||
// Alert Circle
|
||||
QPoint center = alertRect.center();
|
||||
QColor frameColor;
|
||||
if (not alert_alt_text.isEmpty()) frameColor = QColor(255, 255, 255, 75);
|
||||
else frameColor = pulseElement(e2eAlertFrame) ? QColor(255, 255, 255, 75) : QColor(0, 255, 0, 75);
|
||||
p.setPen(QPen(frameColor, 15));
|
||||
p.setBrush(QColor(0, 0, 0, 190));
|
||||
p.drawEllipse(center, size, size);
|
||||
|
||||
// Alert Text
|
||||
QColor txtColor;
|
||||
QFont font;
|
||||
int alert_bottom_adjustment;
|
||||
if (not alert_alt_text.isEmpty()) {
|
||||
font = InterFont(100, QFont::Bold);
|
||||
alert_bottom_adjustment = 5;
|
||||
txtColor = QColor(255, 255, 255, 255);
|
||||
} else {
|
||||
font = InterFont(48, QFont::Bold);
|
||||
alert_bottom_adjustment = 7;
|
||||
txtColor = pulseElement(e2eAlertFrame) ? QColor(255, 255, 255, 255) : QColor(0, 255, 0, 190);
|
||||
}
|
||||
p.setPen(txtColor);
|
||||
p.setFont(font);
|
||||
QFontMetrics fm(p.font());
|
||||
QRect textRect = fm.boundingRect(alertRect, Qt::TextWordWrap, alert_text);
|
||||
textRect.moveCenter({alertRect.center().x(), alertRect.center().y()});
|
||||
textRect.moveBottom(alertRect.bottom() - alertRect.height() / alert_bottom_adjustment);
|
||||
p.drawText(textRect, Qt::AlignCenter, alert_text);
|
||||
|
||||
if (not alert_alt_text.isEmpty()) {
|
||||
// Alert Alternate Text
|
||||
p.setFont(InterFont(80, QFont::Bold));
|
||||
p.setPen(QColor(255, 175, 3, 240));
|
||||
QFontMetrics fmt(p.font());
|
||||
QRect topTextRect = fmt.boundingRect(alertRect, Qt::TextWordWrap, alert_alt_text);
|
||||
topTextRect.moveCenter({alertRect.center().x(), alertRect.center().y()});
|
||||
topTextRect.moveTop(alertRect.top() + alertRect.height() / 3.5);
|
||||
p.drawText(topTextRect, Qt::AlignCenter, alert_alt_text);
|
||||
} else {
|
||||
// Alert Image instead of Top Text
|
||||
QPointF pixmapCenterOffset = QPointF(alert_img.width() / 2.0, alert_img.height() / 2.0);
|
||||
QPointF drawPoint = center - pixmapCenterOffset;
|
||||
p.drawPixmap(drawPoint, alert_img);
|
||||
}
|
||||
}
|
||||
|
||||
void HudRendererSP::drawCurrentSpeedSP(QPainter &p, const QRect &surface_rect) {
|
||||
QString speedStr = QString::number(std::nearbyint(speed));
|
||||
|
||||
p.setFont(InterFont(176, QFont::Bold));
|
||||
HudRenderer::drawText(p, surface_rect.center().x(), 210, speedStr);
|
||||
|
||||
p.setFont(InterFont(66));
|
||||
HudRenderer::drawText(p, surface_rect.center().x(), 290, is_metric ? tr("km/h") : tr("mph"), 200);
|
||||
}
|
||||
|
||||
void HudRendererSP::drawBlinker(QPainter &p, const QRect &surface_rect) {
|
||||
if (!leftBlinkerOn && !rightBlinkerOn) {
|
||||
blinkerFrameCounter = 0;
|
||||
return;
|
||||
}
|
||||
++blinkerFrameCounter;
|
||||
|
||||
const int circleRadius = 44;
|
||||
const int arrowLength = 44;
|
||||
const int x_gap = 180;
|
||||
const int y_offset = 272;
|
||||
|
||||
const int centerX = surface_rect.center().x();
|
||||
const bool hazard = leftBlinkerOn && rightBlinkerOn;
|
||||
|
||||
const QPen bgBorder(Qt::white, 5);
|
||||
const QPen arrowPen(Qt::NoPen);
|
||||
|
||||
p.save();
|
||||
|
||||
auto drawArrow = [&](int cx, int cy, int dir, const QBrush &arrowBrush) {
|
||||
const int bodyLength = arrowLength / 2;
|
||||
const int bodyWidth = arrowLength / 2;
|
||||
const int headLength = arrowLength / 2;
|
||||
const int headWidth = arrowLength;
|
||||
|
||||
QPolygon arrow;
|
||||
arrow.reserve(7);
|
||||
arrow << QPoint(cx - dir * bodyLength, cy - bodyWidth / 2)
|
||||
<< QPoint(cx, cy - bodyWidth / 2)
|
||||
<< QPoint(cx, cy - headWidth / 2)
|
||||
<< QPoint(cx + dir * headLength, cy)
|
||||
<< QPoint(cx, cy + headWidth / 2)
|
||||
<< QPoint(cx, cy + bodyWidth / 2)
|
||||
<< QPoint(cx - dir * bodyLength, cy + bodyWidth / 2);
|
||||
|
||||
p.setPen(arrowPen);
|
||||
p.setBrush(arrowBrush);
|
||||
p.drawPolygon(arrow);
|
||||
};
|
||||
|
||||
auto drawCircle = [&](int cx, int cy, const QBrush &bgBrush) {
|
||||
p.setPen(bgBorder);
|
||||
p.setBrush(bgBrush);
|
||||
p.drawEllipse(QPoint(cx, cy), circleRadius, circleRadius);
|
||||
};
|
||||
|
||||
struct BlinkerSide { bool on; int dir; bool blocked; int cx; };
|
||||
const std::array<BlinkerSide, 2> sides = {{
|
||||
{leftBlinkerOn, -1, hazard ? true : (leftBlinkerOn && leftBlindspot), centerX - x_gap},
|
||||
{rightBlinkerOn, 1, hazard ? true : (rightBlinkerOn && rightBlindspot), centerX + x_gap},
|
||||
}};
|
||||
|
||||
for (const auto &s: sides) {
|
||||
if (!s.on) continue;
|
||||
|
||||
QColor bgColor = s.blocked ? QColor(135, 23, 23) : QColor(23, 134, 68);
|
||||
QColor arrowColor = s.blocked ? QColor(66, 12, 12) : QColor(12, 67, 34);
|
||||
if (pulseElement(blinkerFrameCounter)) arrowColor = Qt::white;
|
||||
|
||||
const QBrush bgBrush(bgColor);
|
||||
const QBrush arrowBrush(arrowColor);
|
||||
|
||||
drawCircle(s.cx, y_offset, bgBrush);
|
||||
drawArrow(s.cx, y_offset, s.dir, arrowBrush);
|
||||
}
|
||||
|
||||
p.restore();
|
||||
}
|
||||
|
||||
@@ -8,8 +8,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "selfdrive/ui/qt/onroad/hud.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/helpers.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/onroad/developer_ui/developer_ui.h"
|
||||
|
||||
constexpr int SPEED_LIMIT_AHEAD_VALID_FRAME_THRESHOLD = 5;
|
||||
|
||||
class HudRendererSP : public HudRenderer {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -28,6 +31,14 @@ private:
|
||||
void drawStandstillTimer(QPainter &p, int x, int y);
|
||||
bool pulseElement(int frame);
|
||||
void drawSmartCruiseControlOnroadIcon(QPainter &p, const QRect &surface_rect, int x_offset, int y_offset, std::string name);
|
||||
void drawSpeedLimitSigns(QPainter &p, QRect &sign_rect);
|
||||
void drawUpcomingSpeedLimit(QPainter &p);
|
||||
void drawRoadName(QPainter &p, const QRect &surface_rect);
|
||||
void drawSpeedLimitPreActiveArrow(QPainter &p, QRect &sign_rect);
|
||||
void drawSetSpeedSP(QPainter &p, const QRect &surface_rect);
|
||||
void drawE2eAlert(QPainter &p, const QRect &surface_rect, const QString &alert_alt_text = "");
|
||||
void drawCurrentSpeedSP(QPainter &p, const QRect &surface_rect);
|
||||
void drawBlinker(QPainter &p, const QRect &surface_rect);
|
||||
|
||||
bool lead_status;
|
||||
float lead_d_rel;
|
||||
@@ -63,4 +74,45 @@ private:
|
||||
bool smartCruiseControlVisionEnabled;
|
||||
bool smartCruiseControlVisionActive;
|
||||
int smartCruiseControlVisionFrame;
|
||||
bool smartCruiseControlMapEnabled;
|
||||
bool smartCruiseControlMapActive;
|
||||
int smartCruiseControlMapFrame;
|
||||
float speedLimit;
|
||||
float speedLimitLast;
|
||||
float speedLimitOffset;
|
||||
bool speedLimitValid;
|
||||
bool speedLimitLastValid;
|
||||
float speedLimitFinalLast;
|
||||
bool speedLimitAheadValid;
|
||||
float speedLimitAhead;
|
||||
float speedLimitAheadDistance;
|
||||
float speedLimitAheadDistancePrev;
|
||||
int speedLimitAheadValidFrame;
|
||||
SpeedLimitMode speedLimitMode = SpeedLimitMode::OFF;
|
||||
bool roadName;
|
||||
QString roadNameStr;
|
||||
cereal::LongitudinalPlanSP::SpeedLimit::AssistState speedLimitAssistState;
|
||||
bool speedLimitAssistActive;
|
||||
int speedLimitAssistFrame;
|
||||
QPixmap plus_arrow_up_img;
|
||||
QPixmap minus_arrow_down_img;
|
||||
int e2e_alert_small = 250;
|
||||
int e2e_alert_large = 300;
|
||||
QPixmap green_light_alert_small_img;
|
||||
QPixmap green_light_alert_large_img;
|
||||
bool greenLightAlert;
|
||||
int e2eAlertFrame;
|
||||
int e2eAlertDisplayTimer = 0;
|
||||
bool leadDepartAlert;
|
||||
QPixmap lead_depart_alert_small_img;
|
||||
QPixmap lead_depart_alert_large_img;
|
||||
QString alert_text;
|
||||
QPixmap alert_img;
|
||||
bool hideVEgoUI;
|
||||
bool leftBlinkerOn;
|
||||
bool rightBlinkerOn;
|
||||
bool leftBlindspot;
|
||||
bool rightBlindspot;
|
||||
int blinkerFrameCounter;
|
||||
bool showTurnSignals;
|
||||
};
|
||||
|
||||
@@ -25,8 +25,10 @@ void OnroadWindowSP::updateState(const UIStateSP &s) {
|
||||
|
||||
void OnroadWindowSP::mousePressEvent(QMouseEvent *e) {
|
||||
OnroadWindow::mousePressEvent(e);
|
||||
uiStateSP()->reset_onroad_sleep_timer();
|
||||
}
|
||||
|
||||
void OnroadWindowSP::offroadTransition(bool offroad) {
|
||||
OnroadWindow::offroadTransition(offroad);
|
||||
uiStateSP()->reset_onroad_sleep_timer();
|
||||
}
|
||||
|
||||
@@ -95,13 +95,12 @@ QStringList searchFromList(const QString &query, const QStringList &list) {
|
||||
return list;
|
||||
}
|
||||
|
||||
QStringList search_terms = query.simplified().toLower().split(" ", QString::SkipEmptyParts);
|
||||
QStringList search_terms = query.simplified().toLower().replace(QRegularExpression("[^a-zA-Z0-9\\s]"), " ").split(" ", QString::SkipEmptyParts);
|
||||
QStringList search_results;
|
||||
|
||||
for (const QString &element : list) {
|
||||
if (std::all_of(search_terms.begin(), search_terms.end(), [&](const QString &term) {
|
||||
QString normalized_term = term.normalized(QString::NormalizationForm_KD).toLower();
|
||||
normalized_term.remove(QRegularExpression("[^a-zA-Z0-9\\s]"));
|
||||
QString normalized_element = element.normalized(QString::NormalizationForm_KD).toLower();
|
||||
return normalized_element.contains(normalized_term, Qt::CaseInsensitive);
|
||||
})) {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
@@ -500,7 +501,7 @@ private:
|
||||
|
||||
int getParamValueScaled() {
|
||||
const auto param_value = QString::fromStdString(params.get(key));
|
||||
return static_cast<int>(param_value.toFloat() * 100);
|
||||
return std::nearbyint(param_value.toFloat() * 100.0f);
|
||||
}
|
||||
|
||||
void setParamValueScaled(const int new_value) {
|
||||
@@ -544,10 +545,8 @@ public:
|
||||
main_layout->removeWidget(title_label);
|
||||
hlayout->addWidget(title_label, 1);
|
||||
}
|
||||
if (spacingItem != nullptr && main_layout->indexOf(spacingItem) != -1) {
|
||||
main_layout->removeItem(spacingItem);
|
||||
spacingItem = nullptr;
|
||||
}
|
||||
main_layout->removeItem(spacingItem);
|
||||
spacingItem = nullptr;
|
||||
}
|
||||
|
||||
label.setStyleSheet(label_enabled_style);
|
||||
|
||||
@@ -14,10 +14,10 @@ ExpandableToggleRow::ExpandableToggleRow(const QString ¶m, const QString &ti
|
||||
QObject::connect(this, &ExpandableToggleRow::toggleFlipped, this, &ExpandableToggleRow::toggleClicked);
|
||||
|
||||
collapsibleWidget = new QFrame(this);
|
||||
collapsibleWidget->setContentsMargins(0, 0, 0, 0);
|
||||
collapsibleWidget->setVisible(false);
|
||||
QVBoxLayout *collapsible_layout = new QVBoxLayout();
|
||||
collapsibleWidget->setLayout(collapsible_layout);
|
||||
collapsible_layout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
list = new ListWidgetSP(this, false);
|
||||
|
||||
|
||||
@@ -11,6 +11,15 @@
|
||||
|
||||
void UIStateSP::updateStatus() {
|
||||
UIState::updateStatus();
|
||||
|
||||
if (scene.started && scene.onroadScreenOffControl) {
|
||||
auto selfdriveState = (*sm)["selfdriveState"].getSelfdriveState();
|
||||
if (selfdriveState.getAlertSize() != cereal::SelfdriveState::AlertSize::NONE) {
|
||||
reset_onroad_sleep_timer();
|
||||
} else if (scene.onroadScreenOffTimer > 0) {
|
||||
scene.onroadScreenOffTimer--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UIStateSP::UIStateSP(QObject *parent) : UIState(parent) {
|
||||
@@ -20,7 +29,7 @@ UIStateSP::UIStateSP(QObject *parent) : UIState(parent) {
|
||||
"wideRoadCameraState", "managerState", "selfdriveState", "longitudinalPlan",
|
||||
"modelManagerSP", "selfdriveStateSP", "longitudinalPlanSP", "backupManagerSP",
|
||||
"carControl", "gpsLocationExternal", "gpsLocation", "liveTorqueParameters",
|
||||
"carStateSP", "liveParameters"
|
||||
"carStateSP", "liveParameters", "liveMapDataSP"
|
||||
});
|
||||
|
||||
// update timer
|
||||
@@ -53,6 +62,26 @@ void ui_update_params_sp(UIStateSP *s) {
|
||||
auto params = Params();
|
||||
s->scene.dev_ui_info = std::atoi(params.get("DevUIInfo").c_str());
|
||||
s->scene.standstill_timer = params.getBool("StandstillTimer");
|
||||
s->scene.speed_limit_mode = std::atoi(params.get("SpeedLimitMode").c_str());
|
||||
s->scene.road_name = params.getBool("RoadNameToggle");
|
||||
s->scene.trueVEgoUI = params.getBool("TrueVEgoUI");
|
||||
s->scene.hideVEgoUI = params.getBool("HideVEgoUI");
|
||||
|
||||
// Onroad Screen Brightness
|
||||
s->scene.onroadScreenOffBrightness = std::atoi(params.get("OnroadScreenOffBrightness").c_str());
|
||||
s->scene.onroadScreenOffControl = params.getBool("OnroadScreenOffControl");
|
||||
s->scene.onroadScreenOffTimerParam = std::atoi(params.get("OnroadScreenOffTimer").c_str());
|
||||
s->reset_onroad_sleep_timer();
|
||||
|
||||
s->scene.turn_signals = params.getBool("ShowTurnSignals");
|
||||
}
|
||||
|
||||
void UIStateSP::reset_onroad_sleep_timer() {
|
||||
if (scene.onroadScreenOffTimerParam >= 0 and scene.onroadScreenOffControl) {
|
||||
scene.onroadScreenOffTimer = scene.onroadScreenOffTimerParam * UI_FREQ;
|
||||
} else {
|
||||
scene.onroadScreenOffTimer = -1;
|
||||
}
|
||||
}
|
||||
|
||||
DeviceSP::DeviceSP(QObject *parent) : Device(parent) {
|
||||
|
||||
@@ -61,6 +61,7 @@ public:
|
||||
return user.user_id.toLower() != "unregisteredsponsor" && user.user_id.toLower() != "temporarysponsor";
|
||||
});
|
||||
}
|
||||
void reset_onroad_sleep_timer();
|
||||
|
||||
signals:
|
||||
void sunnylinkRoleChanged(bool subscriber);
|
||||
|
||||
@@ -10,4 +10,12 @@
|
||||
typedef struct UISceneSP : UIScene {
|
||||
int dev_ui_info = 0;
|
||||
bool standstill_timer = false;
|
||||
int speed_limit_mode = 0;
|
||||
bool road_name = false;
|
||||
int onroadScreenOffBrightness, onroadScreenOffTimer = 0;
|
||||
bool onroadScreenOffControl;
|
||||
int onroadScreenOffTimerParam;
|
||||
bool trueVEgoUI;
|
||||
bool hideVEgoUI;
|
||||
bool turn_signals = false;
|
||||
} UISceneSP;
|
||||
|
||||
@@ -29,7 +29,7 @@ UI_DELAY = 0.5 # may be slower on CI?
|
||||
TEST_ROUTE = "a2a0ccea32023010|2023-07-27--13-01-19"
|
||||
|
||||
STREAMS: list[tuple[VisionStreamType, CameraConfig, bytes]] = []
|
||||
OFFROAD_ALERTS = ['Offroad_IsTakingSnapshot', ]
|
||||
OFFROAD_ALERTS = ['Offroad_StorageMissing', 'Offroad_IsTakingSnapshot']
|
||||
DATA: dict[str, capnp.lib.capnp._DynamicStructBuilder] = dict.fromkeys(
|
||||
["carParams", "deviceState", "pandaStates", "controlsState", "selfdriveState",
|
||||
"liveCalibration", "modelV2", "radarState", "driverMonitoringState", "carState",
|
||||
|
||||
@@ -133,14 +133,6 @@ Please use caution when using this feature. Only use the blinker when traffic an
|
||||
</context>
|
||||
<context>
|
||||
<name>Brightness</name>
|
||||
<message>
|
||||
<source>Brightness</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Overrides the brightness of the device.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Auto (Dark)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -149,6 +141,14 @@ Please use caution when using this feature. Only use the blinker when traffic an
|
||||
<source>Auto</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Global Brightness</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Overrides the brightness of the device. This applies to both onroad and offroad screens. </source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ConfirmationDialog</name>
|
||||
@@ -250,6 +250,14 @@ This only toggles the visibility of the controls; it does not toggle the actual
|
||||
<source>Quickboot mode requires updates to be disabled.<br>Enable 'Disable Updates' in the Software panel first.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Copyparty service</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copyparty is a very capable file server, you can use it to download your routes, view your logs and even make some edits on some files from your browser. Requires you to connect to your comma locally via it's IP.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DevicePanel</name>
|
||||
@@ -464,15 +472,6 @@ Steering lag calibration is complete.</source>
|
||||
<source>Wake-Up Behavior</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Interactivity Timeout</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Apply a custom timeout for settings UI.
|
||||
This is the time after which settings UI closes automatically if user is not interacting with the screen.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reboot</source>
|
||||
<translation type="unfinished">إعادة التشغيل</translation>
|
||||
@@ -517,10 +516,6 @@ This is the time after which settings UI closes automatically if user is not int
|
||||
<source>Exit Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⁍ Default: Device will boot/wake-up normally & will be ready to engage.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -533,6 +528,34 @@ This is the time after which settings UI closes automatically if user is not int
|
||||
<source>Controls state of the device after boot/sleep.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Onroad Uploads</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DisplayPanel</name>
|
||||
<message>
|
||||
<source>Onroad Screen: Reduced Brightness</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Turn off device screen or reduce brightness after driving starts. It automatically brightens again when screen is touched or a visible alert is displayed.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Interactivity Timeout</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Apply a custom timeout for settings UI.
|
||||
This is the time after which settings UI closes automatically if user is not interacting with the screen.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DriveStats</name>
|
||||
@@ -594,6 +617,61 @@ This is the time after which settings UI closes automatically if user is not int
|
||||
<translation>تشغيل وضع الراحة</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ExternalStorageControl</name>
|
||||
<message>
|
||||
<source>External Storage</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Extend your comma device's storage by inserting a USB drive into the aux port.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>CHECK</source>
|
||||
<translation type="unfinished">التحقق</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>MOUNT</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>UNMOUNT</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>FORMAT</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to format this drive? This will erase all data.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Format</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>formatting</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>insert drive</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>needs format</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>mounting</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>unmounting</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FirehosePanel</name>
|
||||
<message>
|
||||
@@ -649,6 +727,63 @@ Firehose Mode allows you to maximize your training data uploads to improve openp
|
||||
<translation>MAX</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>HudRendererSP</name>
|
||||
<message>
|
||||
<source>km/h</source>
|
||||
<translation type="unfinished">كم/س</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>mph</source>
|
||||
<translation type="unfinished">ميل/س</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>GREEN
|
||||
LIGHT</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>LEAD VEHICLE
|
||||
DEPARTING</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SPEED</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>LIMIT</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Near</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>km</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>m</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>mi</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ft</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>AHEAD</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>MAX</source>
|
||||
<translation type="unfinished">MAX</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>HyundaiSettings</name>
|
||||
<message>
|
||||
@@ -767,6 +902,18 @@ Firehose Mode allows you to maximize your training data uploads to improve openp
|
||||
<source>This platform supports limited MADS settings.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enforce Torque Lateral Control</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable this to enforce sunnypilot to steer with Torque lateral control.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Customize Params</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>LongitudinalPanel</name>
|
||||
@@ -790,6 +937,34 @@ Firehose Mode allows you to maximize your training data uploads to improve openp
|
||||
<source>Start the vehicle to check vehicle compatibility.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Intelligent Cruise Button Management (ICBM) (Alpha)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>When enabled, sunnypilot will attempt to manage the built-in cruise control buttons by emulating button presses for limited longitudinal control.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Smart Cruise Control - Vision</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use vision path predictions to estimate the appropriate speed to drive through turns ahead.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Smart Cruise Control - Map</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use map data to estimate the appropriate speed to drive through turns ahead.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Speed Limit</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MadsSettings</name>
|
||||
@@ -1048,6 +1223,18 @@ The default software delay value is 0.2</source>
|
||||
<source>Total Delay:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Lane Turn Desires</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Adjust Lane Turn Speed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Set the maximum speed for lane turn desires. Default is 19 %1.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MultiOptionDialog</name>
|
||||
@@ -1169,10 +1356,6 @@ The default software delay value is 0.2</source>
|
||||
<source>An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install.</source>
|
||||
<translation>يتم تنزيل تحديث لنظام تشغيل جهازك في الخلفية. سيطلَب منك التحديث عندما يصبح جاهزاً للتثبيت.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>NVMe drive not mounted.</source>
|
||||
<translation>محرك NVMe غير مثبَّت.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -1211,6 +1394,10 @@ The default software delay value is 0.2</source>
|
||||
%1</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Unsupported branch detected</b> - The current version of <b><u>%1</u></b> branch is no longer supported on the comma three. Please go to <b>[Device > Software]</b> and install a supported branch with <b><u>-tici</u></b> in the branch name for the comma three.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>OffroadHome</name>
|
||||
@@ -1597,6 +1784,59 @@ Warning: You are on a metered connection!</source>
|
||||
<source>sunnypilot</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>None</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Fixed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Percent</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Car
|
||||
Only</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Map
|
||||
Only</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Car
|
||||
First</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Map
|
||||
First</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Combined
|
||||
Data</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Off</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Information</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Warning</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Assist</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SettingsWindow</name>
|
||||
@@ -1691,6 +1931,10 @@ Warning: You are on a metered connection!</source>
|
||||
<source>Developer</source>
|
||||
<translation type="unfinished">المطور</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Display</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SetupWidget</name>
|
||||
@@ -1927,6 +2171,84 @@ Warning: You are on a metered connection!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SpeedLimitPolicy</name>
|
||||
<message>
|
||||
<source>Back</source>
|
||||
<translation type="unfinished">السابق</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Speed Limit Source</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Car Only: Use Speed Limit data only from Car</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Map Only: Use Speed Limit data only from OpenStreetMaps</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Car First: Use Speed Limit data from Car if available, else use from OpenStreetMaps</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Map First: Use Speed Limit data from OpenStreetMaps if available, else use from Car</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Combined: Use combined Speed Limit data from Car & OpenStreetMaps</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SpeedLimitSettings</name>
|
||||
<message>
|
||||
<source>Back</source>
|
||||
<translation type="unfinished">السابق</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Speed Limit</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Customize Source</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Speed Limit Offset</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ None: No Offset</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Fixed: Adds a fixed offset [Speed Limit + Offset]</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Percent: Adds a percent offset [Speed Limit + (Offset % Speed Limit)]</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Off: Disables the Speed Limit functions.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Information: Displays the current road's speed limit.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Warning: Provides a warning when exceeding the current road's speed limit.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Assist: Adjusts the vehicle's cruise speed based on the current road's speed limit when operating the +/- buttons.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SshControl</name>
|
||||
<message>
|
||||
@@ -2309,6 +2631,60 @@ Warning: You are on a metered connection!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TorqueLateralControlCustomParams</name>
|
||||
<message>
|
||||
<source>Manual Real-Time Tuning</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Lateral Acceleration Factor</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Friction</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Real-time and Offline</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Offline Only</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TorqueLateralControlSettings</name>
|
||||
<message>
|
||||
<source>Self-Tune</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enables self-tune for Torque lateral control for platforms that do not use Torque lateral control by default.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Less Restrict Settings for Self-Tune (Beta)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Less strict settings when using Self-Tune. This allows torqued to be more forgiving when learning values.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Custom Tuning</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TreeOptionDialog</name>
|
||||
<message>
|
||||
@@ -2319,6 +2695,10 @@ Warning: You are on a metered connection!</source>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">إلغاء</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Favorites</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>VisualsPanel</name>
|
||||
@@ -2362,6 +2742,91 @@ Warning: You are on a metered connection!</source>
|
||||
<source>Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control).</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Tesla Rainbow Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>A beautiful rainbow effect on the path the model wants to take.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>It</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>does not</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>affect driving in any way.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Standstill Timer</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Show a timer on the HUD when the car is at a standstill.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Display Road Name</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Displays the name of the road the car is traveling on. The OpenStreetMap database of the location must be downloaded from the OSM panel to fetch the road name.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Green Traffic Light Alert (Beta)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>A chime and on-screen alert will play when the traffic light you are waiting for turns green and you have no vehicle in front of you.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Lead Departure Alert (Beta)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>A chime and on-screen alert will play when you are stopped, and the vehicle in front of you start moving.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Speedometer: Always Display True Speed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Always display the true vehicle current speed from wheel speed sensors.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Speedometer: Hide from Onroad Screen</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Right</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Right &&
|
||||
Bottom</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer UI</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Display real-time parameters and metrics from various sources.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>WiFiPromptWidget</name>
|
||||
|
||||
@@ -133,14 +133,6 @@ Please use caution when using this feature. Only use the blinker when traffic an
|
||||
</context>
|
||||
<context>
|
||||
<name>Brightness</name>
|
||||
<message>
|
||||
<source>Brightness</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Overrides the brightness of the device.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Auto (Dark)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -149,6 +141,14 @@ Please use caution when using this feature. Only use the blinker when traffic an
|
||||
<source>Auto</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Global Brightness</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Overrides the brightness of the device. This applies to both onroad and offroad screens. </source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ConfirmationDialog</name>
|
||||
@@ -250,6 +250,14 @@ This only toggles the visibility of the controls; it does not toggle the actual
|
||||
<source>Quickboot mode requires updates to be disabled.<br>Enable 'Disable Updates' in the Software panel first.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Copyparty service</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copyparty is a very capable file server, you can use it to download your routes, view your logs and even make some edits on some files from your browser. Requires you to connect to your comma locally via it's IP.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DevicePanel</name>
|
||||
@@ -464,15 +472,6 @@ Steering lag calibration is complete.</source>
|
||||
<source>Wake-Up Behavior</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Interactivity Timeout</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Apply a custom timeout for settings UI.
|
||||
This is the time after which settings UI closes automatically if user is not interacting with the screen.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reboot</source>
|
||||
<translation type="unfinished">Neustart</translation>
|
||||
@@ -517,10 +516,6 @@ This is the time after which settings UI closes automatically if user is not int
|
||||
<source>Exit Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⁍ Default: Device will boot/wake-up normally & will be ready to engage.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -533,6 +528,34 @@ This is the time after which settings UI closes automatically if user is not int
|
||||
<source>Controls state of the device after boot/sleep.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Onroad Uploads</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DisplayPanel</name>
|
||||
<message>
|
||||
<source>Onroad Screen: Reduced Brightness</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Turn off device screen or reduce brightness after driving starts. It automatically brightens again when screen is touched or a visible alert is displayed.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Interactivity Timeout</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Apply a custom timeout for settings UI.
|
||||
This is the time after which settings UI closes automatically if user is not interacting with the screen.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DriveStats</name>
|
||||
@@ -594,6 +617,61 @@ This is the time after which settings UI closes automatically if user is not int
|
||||
<translation>ENTSPANNTER MODUS AN</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ExternalStorageControl</name>
|
||||
<message>
|
||||
<source>External Storage</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Extend your comma device's storage by inserting a USB drive into the aux port.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>CHECK</source>
|
||||
<translation type="unfinished">ÜBERPRÜFEN</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>MOUNT</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>UNMOUNT</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>FORMAT</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to format this drive? This will erase all data.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Format</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>formatting</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>insert drive</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>needs format</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>mounting</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>unmounting</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FirehosePanel</name>
|
||||
<message>
|
||||
@@ -645,6 +723,63 @@ Firehose Mode allows you to maximize your training data uploads to improve openp
|
||||
<translation>MAX</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>HudRendererSP</name>
|
||||
<message>
|
||||
<source>km/h</source>
|
||||
<translation type="unfinished">km/h</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>mph</source>
|
||||
<translation type="unfinished">mph</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>GREEN
|
||||
LIGHT</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>LEAD VEHICLE
|
||||
DEPARTING</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SPEED</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>LIMIT</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Near</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>km</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>m</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>mi</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ft</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>AHEAD</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>MAX</source>
|
||||
<translation type="unfinished">MAX</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>HyundaiSettings</name>
|
||||
<message>
|
||||
@@ -759,6 +894,18 @@ Firehose Mode allows you to maximize your training data uploads to improve openp
|
||||
<source>This platform supports limited MADS settings.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enforce Torque Lateral Control</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable this to enforce sunnypilot to steer with Torque lateral control.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Customize Params</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>LongitudinalPanel</name>
|
||||
@@ -782,6 +929,34 @@ Firehose Mode allows you to maximize your training data uploads to improve openp
|
||||
<source>Start the vehicle to check vehicle compatibility.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Intelligent Cruise Button Management (ICBM) (Alpha)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>When enabled, sunnypilot will attempt to manage the built-in cruise control buttons by emulating button presses for limited longitudinal control.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Smart Cruise Control - Vision</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use vision path predictions to estimate the appropriate speed to drive through turns ahead.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Smart Cruise Control - Map</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use map data to estimate the appropriate speed to drive through turns ahead.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Speed Limit</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MadsSettings</name>
|
||||
@@ -1040,6 +1215,18 @@ The default software delay value is 0.2</source>
|
||||
<source>Total Delay:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Lane Turn Desires</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Adjust Lane Turn Speed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Set the maximum speed for lane turn desires. Default is 19 %1.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MultiOptionDialog</name>
|
||||
@@ -1157,10 +1344,6 @@ The default software delay value is 0.2</source>
|
||||
<source>An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install.</source>
|
||||
<translation>Ein Update für das Betriebssystem deines Geräts wird im Hintergrund heruntergeladen. Du wirst aufgefordert, das Update zu installieren, sobald es bereit ist.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>NVMe drive not mounted.</source>
|
||||
<translation>NVMe-Laufwerk nicht gemounted.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device temperature too high. System cooling down before starting. Current internal component temperature: %1</source>
|
||||
<translation>Gerätetemperatur zu hoch. Das System kühlt ab, bevor es startet. Aktuelle interne Komponententemperatur: %1</translation>
|
||||
@@ -1203,6 +1386,10 @@ The default software delay value is 0.2</source>
|
||||
%1</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Unsupported branch detected</b> - The current version of <b><u>%1</u></b> branch is no longer supported on the comma three. Please go to <b>[Device > Software]</b> and install a supported branch with <b><u>-tici</u></b> in the branch name for the comma three.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>OffroadHome</name>
|
||||
@@ -1577,6 +1764,59 @@ Warning: You are on a metered connection!</source>
|
||||
<source>sunnypilot</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>None</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Fixed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Percent</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Car
|
||||
Only</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Map
|
||||
Only</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Car
|
||||
First</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Map
|
||||
First</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Combined
|
||||
Data</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Off</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Information</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Warning</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Assist</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SettingsWindow</name>
|
||||
@@ -1671,6 +1911,10 @@ Warning: You are on a metered connection!</source>
|
||||
<source>Developer</source>
|
||||
<translation type="unfinished">Entwickler</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Display</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SetupWidget</name>
|
||||
@@ -1909,6 +2153,84 @@ Warning: You are on a metered connection!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SpeedLimitPolicy</name>
|
||||
<message>
|
||||
<source>Back</source>
|
||||
<translation type="unfinished">Zurück</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Speed Limit Source</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Car Only: Use Speed Limit data only from Car</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Map Only: Use Speed Limit data only from OpenStreetMaps</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Car First: Use Speed Limit data from Car if available, else use from OpenStreetMaps</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Map First: Use Speed Limit data from OpenStreetMaps if available, else use from Car</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Combined: Use combined Speed Limit data from Car & OpenStreetMaps</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SpeedLimitSettings</name>
|
||||
<message>
|
||||
<source>Back</source>
|
||||
<translation type="unfinished">Zurück</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Speed Limit</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Customize Source</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Speed Limit Offset</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ None: No Offset</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Fixed: Adds a fixed offset [Speed Limit + Offset]</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Percent: Adds a percent offset [Speed Limit + (Offset % Speed Limit)]</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Off: Disables the Speed Limit functions.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Information: Displays the current road's speed limit.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Warning: Provides a warning when exceeding the current road's speed limit.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Assist: Adjusts the vehicle's cruise speed based on the current road's speed limit when operating the +/- buttons.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SshControl</name>
|
||||
<message>
|
||||
@@ -2291,6 +2613,60 @@ Warning: You are on a metered connection!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TorqueLateralControlCustomParams</name>
|
||||
<message>
|
||||
<source>Manual Real-Time Tuning</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Lateral Acceleration Factor</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Friction</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Real-time and Offline</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Offline Only</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TorqueLateralControlSettings</name>
|
||||
<message>
|
||||
<source>Self-Tune</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enables self-tune for Torque lateral control for platforms that do not use Torque lateral control by default.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Less Restrict Settings for Self-Tune (Beta)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Less strict settings when using Self-Tune. This allows torqued to be more forgiving when learning values.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Custom Tuning</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TreeOptionDialog</name>
|
||||
<message>
|
||||
@@ -2301,6 +2677,10 @@ Warning: You are on a metered connection!</source>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">Abbrechen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Favorites</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>VisualsPanel</name>
|
||||
@@ -2344,6 +2724,91 @@ Warning: You are on a metered connection!</source>
|
||||
<source>Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control).</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Tesla Rainbow Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>A beautiful rainbow effect on the path the model wants to take.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>It</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>does not</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>affect driving in any way.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Standstill Timer</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Show a timer on the HUD when the car is at a standstill.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Display Road Name</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Displays the name of the road the car is traveling on. The OpenStreetMap database of the location must be downloaded from the OSM panel to fetch the road name.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Green Traffic Light Alert (Beta)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>A chime and on-screen alert will play when the traffic light you are waiting for turns green and you have no vehicle in front of you.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Lead Departure Alert (Beta)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>A chime and on-screen alert will play when you are stopped, and the vehicle in front of you start moving.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Speedometer: Always Display True Speed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Always display the true vehicle current speed from wheel speed sensors.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Speedometer: Hide from Onroad Screen</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Right</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Right &&
|
||||
Bottom</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer UI</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Display real-time parameters and metrics from various sources.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>WiFiPromptWidget</name>
|
||||
|
||||
@@ -133,14 +133,6 @@ Please use caution when using this feature. Only use the blinker when traffic an
|
||||
</context>
|
||||
<context>
|
||||
<name>Brightness</name>
|
||||
<message>
|
||||
<source>Brightness</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Overrides the brightness of the device.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Auto (Dark)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -149,6 +141,14 @@ Please use caution when using this feature. Only use the blinker when traffic an
|
||||
<source>Auto</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Global Brightness</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Overrides the brightness of the device. This applies to both onroad and offroad screens. </source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ConfirmationDialog</name>
|
||||
@@ -250,6 +250,14 @@ This only toggles the visibility of the controls; it does not toggle the actual
|
||||
<source>Quickboot mode requires updates to be disabled.<br>Enable 'Disable Updates' in the Software panel first.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Copyparty service</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copyparty is a very capable file server, you can use it to download your routes, view your logs and even make some edits on some files from your browser. Requires you to connect to your comma locally via it's IP.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DevicePanel</name>
|
||||
@@ -468,15 +476,6 @@ La calibración del retraso de la dirección está completa.</translation>
|
||||
<source>Wake-Up Behavior</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Interactivity Timeout</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Apply a custom timeout for settings UI.
|
||||
This is the time after which settings UI closes automatically if user is not interacting with the screen.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reboot</source>
|
||||
<translation type="unfinished">Reiniciar</translation>
|
||||
@@ -521,10 +520,6 @@ This is the time after which settings UI closes automatically if user is not int
|
||||
<source>Exit Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⁍ Default: Device will boot/wake-up normally & will be ready to engage.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -537,6 +532,34 @@ This is the time after which settings UI closes automatically if user is not int
|
||||
<source>Controls state of the device after boot/sleep.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Onroad Uploads</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DisplayPanel</name>
|
||||
<message>
|
||||
<source>Onroad Screen: Reduced Brightness</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Turn off device screen or reduce brightness after driving starts. It automatically brightens again when screen is touched or a visible alert is displayed.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Interactivity Timeout</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Apply a custom timeout for settings UI.
|
||||
This is the time after which settings UI closes automatically if user is not interacting with the screen.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DriveStats</name>
|
||||
@@ -598,6 +621,61 @@ This is the time after which settings UI closes automatically if user is not int
|
||||
<translation>MODO CHILL</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ExternalStorageControl</name>
|
||||
<message>
|
||||
<source>External Storage</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Extend your comma device's storage by inserting a USB drive into the aux port.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>CHECK</source>
|
||||
<translation type="unfinished">VERIFICAR</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>MOUNT</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>UNMOUNT</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>FORMAT</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to format this drive? This will erase all data.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Format</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>formatting</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>insert drive</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>needs format</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>mounting</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>unmounting</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FirehosePanel</name>
|
||||
<message>
|
||||
@@ -649,6 +727,63 @@ Firehose Mode allows you to maximize your training data uploads to improve openp
|
||||
<translation>MAX</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>HudRendererSP</name>
|
||||
<message>
|
||||
<source>km/h</source>
|
||||
<translation type="unfinished">km/h</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>mph</source>
|
||||
<translation type="unfinished">mph</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>GREEN
|
||||
LIGHT</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>LEAD VEHICLE
|
||||
DEPARTING</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SPEED</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>LIMIT</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Near</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>km</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>m</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>mi</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ft</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>AHEAD</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>MAX</source>
|
||||
<translation type="unfinished">MAX</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>HyundaiSettings</name>
|
||||
<message>
|
||||
@@ -763,6 +898,18 @@ Firehose Mode allows you to maximize your training data uploads to improve openp
|
||||
<source>This platform supports limited MADS settings.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enforce Torque Lateral Control</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable this to enforce sunnypilot to steer with Torque lateral control.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Customize Params</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>LongitudinalPanel</name>
|
||||
@@ -786,6 +933,34 @@ Firehose Mode allows you to maximize your training data uploads to improve openp
|
||||
<source>Start the vehicle to check vehicle compatibility.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Intelligent Cruise Button Management (ICBM) (Alpha)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>When enabled, sunnypilot will attempt to manage the built-in cruise control buttons by emulating button presses for limited longitudinal control.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Smart Cruise Control - Vision</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use vision path predictions to estimate the appropriate speed to drive through turns ahead.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Smart Cruise Control - Map</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use map data to estimate the appropriate speed to drive through turns ahead.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Speed Limit</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MadsSettings</name>
|
||||
@@ -1044,6 +1219,18 @@ The default software delay value is 0.2</source>
|
||||
<source>Total Delay:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Lane Turn Desires</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Adjust Lane Turn Speed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Set the maximum speed for lane turn desires. Default is 19 %1.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MultiOptionDialog</name>
|
||||
@@ -1165,10 +1352,6 @@ The default software delay value is 0.2</source>
|
||||
<source>An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install.</source>
|
||||
<translation>Se está descargando una actualización del sistema operativo de su dispositivo en segundo plano. Se le pedirá que actualice cuando esté listo para instalarse.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>NVMe drive not mounted.</source>
|
||||
<translation>Unidad NVMe no montada.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -1207,6 +1390,10 @@ The default software delay value is 0.2</source>
|
||||
%1</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Unsupported branch detected</b> - The current version of <b><u>%1</u></b> branch is no longer supported on the comma three. Please go to <b>[Device > Software]</b> and install a supported branch with <b><u>-tici</u></b> in the branch name for the comma three.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>OffroadHome</name>
|
||||
@@ -1581,6 +1768,59 @@ Warning: You are on a metered connection!</source>
|
||||
<source>sunnypilot</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>None</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Fixed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Percent</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Car
|
||||
Only</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Map
|
||||
Only</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Car
|
||||
First</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Map
|
||||
First</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Combined
|
||||
Data</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Off</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Information</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Warning</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Assist</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SettingsWindow</name>
|
||||
@@ -1675,6 +1915,10 @@ Warning: You are on a metered connection!</source>
|
||||
<source>Developer</source>
|
||||
<translation type="unfinished">Desarrollador</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Display</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SetupWidget</name>
|
||||
@@ -1911,6 +2155,84 @@ Warning: You are on a metered connection!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SpeedLimitPolicy</name>
|
||||
<message>
|
||||
<source>Back</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Speed Limit Source</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Car Only: Use Speed Limit data only from Car</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Map Only: Use Speed Limit data only from OpenStreetMaps</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Car First: Use Speed Limit data from Car if available, else use from OpenStreetMaps</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Map First: Use Speed Limit data from OpenStreetMaps if available, else use from Car</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Combined: Use combined Speed Limit data from Car & OpenStreetMaps</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SpeedLimitSettings</name>
|
||||
<message>
|
||||
<source>Back</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Speed Limit</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Customize Source</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Speed Limit Offset</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ None: No Offset</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Fixed: Adds a fixed offset [Speed Limit + Offset]</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Percent: Adds a percent offset [Speed Limit + (Offset % Speed Limit)]</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Off: Disables the Speed Limit functions.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Information: Displays the current road's speed limit.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Warning: Provides a warning when exceeding the current road's speed limit.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>⦿ Assist: Adjusts the vehicle's cruise speed based on the current road's speed limit when operating the +/- buttons.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SshControl</name>
|
||||
<message>
|
||||
@@ -2293,6 +2615,60 @@ Warning: You are on a metered connection!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TorqueLateralControlCustomParams</name>
|
||||
<message>
|
||||
<source>Manual Real-Time Tuning</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Lateral Acceleration Factor</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Friction</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Real-time and Offline</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Offline Only</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TorqueLateralControlSettings</name>
|
||||
<message>
|
||||
<source>Self-Tune</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enables self-tune for Torque lateral control for platforms that do not use Torque lateral control by default.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Less Restrict Settings for Self-Tune (Beta)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Less strict settings when using Self-Tune. This allows torqued to be more forgiving when learning values.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Custom Tuning</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TreeOptionDialog</name>
|
||||
<message>
|
||||
@@ -2303,6 +2679,10 @@ Warning: You are on a metered connection!</source>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">Cancelar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Favorites</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>VisualsPanel</name>
|
||||
@@ -2346,6 +2726,91 @@ Warning: You are on a metered connection!</source>
|
||||
<source>Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control).</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Tesla Rainbow Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>A beautiful rainbow effect on the path the model wants to take.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>It</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>does not</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>affect driving in any way.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Standstill Timer</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Show a timer on the HUD when the car is at a standstill.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Display Road Name</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Displays the name of the road the car is traveling on. The OpenStreetMap database of the location must be downloaded from the OSM panel to fetch the road name.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Green Traffic Light Alert (Beta)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>A chime and on-screen alert will play when the traffic light you are waiting for turns green and you have no vehicle in front of you.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Lead Departure Alert (Beta)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>A chime and on-screen alert will play when you are stopped, and the vehicle in front of you start moving.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Speedometer: Always Display True Speed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Always display the true vehicle current speed from wheel speed sensors.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Speedometer: Hide from Onroad Screen</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Right</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Right &&
|
||||
Bottom</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer UI</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Display real-time parameters and metrics from various sources.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>WiFiPromptWidget</name>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user