Compare commits

..

161 Commits

Author SHA1 Message Date
DevTekVE a77d1f7eb0 Add ButtonHoldTracker for button hold logic and tests
Introduce a new `ButtonHoldTracker` class to manage button hold durations, replacing manual timer handling in `ExperimentalSwitcher`. Updated `ExperimentalSwitcher` to leverage this implementation for cleaner and more modular code. Added comprehensive unit tests for both `ButtonHoldTracker` and `ExperimentalSwitcher` to ensure functionality and edge case coverage.
2025-01-19 12:58:29 +01:00
Jason Wen 6eb6af5785 Merge branch 'dec-redo' into master-dev-c3-new 2025-01-19 03:39:30 -05:00
Jason Wen 7471bd4029 init 2025-01-19 03:18:05 -05:00
Jason Wen 767f057112 Merge branch 'master-new' into dec-redo 2025-01-19 02:55:46 -05:00
Jason Wen 6ef47dafcf ui: display DEC status via mode button (#592) 2025-01-19 02:54:58 -05:00
Jason Wen 3f6ac7e77a Merge branch 'ui-model-selector-rich' into master-dev-c3-new
# Conflicts:
#	opendbc_repo
#	panda
2025-01-19 02:51:06 -05:00
Jason Wen d8040eea3f Merge branch 'master-new' into ui-model-selector-rich 2025-01-19 02:50:22 -05:00
Jason Wen d223135ee3 Merge branch 'master-new' into ui-model-selector-rich 2025-01-19 02:49:13 -05:00
Jason Wen 8f29ddba45 ui: Model Selector: display prompt with rich text widget 2025-01-19 02:48:32 -05:00
Jason Wen b7c3072a4c Merge branch 'mads-honda-states' into master-dev-c3-new 2025-01-18 23:57:32 -05:00
Jason Wen 3cba24f93a MADS: Honda: Allow steering 2025-01-18 23:57:05 -05:00
Jason Wen f2edd589ba fix 2025-01-18 22:04:30 -05:00
Jason Wen bf0a7b4494 migrate to sp only 2025-01-18 22:02:40 -05:00
Jason Wen 19b96003dc use another method for drawing 2025-01-18 21:51:49 -05:00
Kumar 10ee25d199 Update constants.py 2025-01-18 19:48:02 -07:00
Kumar cd6fb642bd Update dec.py 2025-01-18 19:46:19 -07:00
Jason Wen 3d35164287 even dimmer 2025-01-18 21:43:14 -05:00
Jason Wen a9ca9bbdf8 should be active and dimmer 2025-01-18 21:35:27 -05:00
Jason Wen 0737f311b8 add opacity 2025-01-18 21:31:01 -05:00
Jason Wen dc45d3043c try this 2025-01-18 21:22:55 -05:00
Jason Wen 2eefd0aaf5 visuals for DEC 2025-01-18 21:12:19 -05:00
Jason Wen cb9d92dc3c Merge branch 'master-new' into dec-redo 2025-01-18 20:55:35 -05:00
Jason Wen 2525fdc350 Merge branch 'mads-honda-states' into master-dev-c3-new 2025-01-18 20:41:18 -05:00
Jason Wen 9eb36a0b7e fix icons 2025-01-18 20:41:01 -05:00
Jason Wen b5a5d94a2c bring them back 2025-01-18 20:39:05 -05:00
Jason Wen a93dc0047d Merge branch 'mads-honda-states' into master-dev-c3-new 2025-01-18 16:35:34 -05:00
Jason Wen 25d195df72 try this 2025-01-18 16:35:27 -05:00
Jason Wen 3fc2f70eb8 nuke them all to test 2025-01-18 16:34:32 -05:00
Jason Wen 64058c4b7c Merge branch 'mads-honda-states' into master-dev-c3-new 2025-01-18 15:48:12 -05:00
Jason Wen 3044aa6133 bump opendbc 2025-01-18 15:48:01 -05:00
Jason Wen f39f76182a Merge branch 'mads-honda-states' into master-dev-c3-new 2025-01-18 15:45:07 -05:00
Jason Wen 15567bf605 Merge branch 'master-new' into master-dev-c3-new 2025-01-18 15:45:02 -05:00
Jason Wen 3b090e0b01 Merge branch 'master-new' into mads-honda-states 2025-01-18 15:44:51 -05:00
Jason Wen df3e848965 MADS: Honda: Cluster icons and events updates 2025-01-18 15:43:46 -05:00
DevTekVE b3e3d1b384 Fix lead detection fallback for weighted average check.
Add a fallback value of -1 when computing the weighted average to prevent errors caused by invalid or None values. This ensures robust lead detection and avoids potential crashes or undefined behavior.
2025-01-18 20:48:06 +01:00
DevTekVE b13356d267 Merge branch 'master-new' into dec-redo 2025-01-18 20:41:04 +01:00
rav4kumar 0089096d12 Update slow-down logic and constants for improved behavior
Adjust the slowdown scaling factor and anomaly handling to refine behavior without abrupt resets. Modify constants to increase window size and adjust probabilities and distances for smoother adaptation. Update version to reflect the new changes.
2025-01-18 11:26:02 -07:00
rav4kumar 3d135f9831 Revert "dec: how good is FirstOrderFilter?"
This reverts commit 01e06df542.
2025-01-18 11:12:10 -07:00
rav4kumar a219046981 Revert "Update dec.py"
This reverts commit 3f29ccbd99.
2025-01-18 11:12:03 -07:00
rav4kumar 2c9ffdbf03 Revert "dec: faster ?"
This reverts commit 40259cd22a.
2025-01-18 11:11:57 -07:00
Jason Wen 5014b42650 Merge branch 'ui-regulatory-hide' into master-dev-c3-new 2025-01-17 21:48:20 -05:00
Jason Wen c1f897168a ui: Hide regulatory button on non-comma devices 2025-01-17 21:45:51 -05:00
Jason Wen 301174b19a Merge branch 'ui-device-offroad' into master-dev-c3-new 2025-01-17 21:29:58 -05:00
Jason Wen 1b139c4ca1 ui: Transition offroad state for Device panel buttons 2025-01-17 21:29:46 -05:00
Jason Wen 745e7b0b28 Merge branch 'master-new' into master-dev-c3-new 2025-01-17 21:23:34 -05:00
Jason Wen 1f328c9fda Revert "ui: driver view window should use uiStateSP"
This reverts commit c08b18936d.
2025-01-17 15:02:49 -05:00
Jason Wen eab69c0f3d Revert "try this"
This reverts commit bd8a93af8b.
2025-01-17 15:02:47 -05:00
Jason Wen 97fda2f918 Revert "more"
This reverts commit 2f5f708c2b.
2025-01-17 15:02:44 -05:00
Jason Wen 03e10db82e Merge branch 'ui-dm-cam-freeze' into master-dev-c3-new 2025-01-17 14:59:14 -05:00
Jason Wen 2f5f708c2b more 2025-01-17 14:59:06 -05:00
Jason Wen 413fc15cf8 Merge branch 'ui-dm-cam-freeze' into master-dev-c3-new 2025-01-17 14:52:54 -05:00
Jason Wen bd8a93af8b try this 2025-01-17 14:52:42 -05:00
Jason Wen 928bec2acc Merge branch 'ui-dm-cam-freeze' into master-dev-c3-new 2025-01-17 14:37:39 -05:00
Jason Wen c08b18936d ui: driver view window should use uiStateSP 2025-01-17 14:37:23 -05:00
Jason Wen 5f94110b7a no need 2025-01-17 12:12:51 -05:00
Jason Wen bca0e7862f Merge branch 'sentry-sp' into master-dev-c3-new 2025-01-17 12:03:17 -05:00
Jason Wen 45c47d0c48 new endpoint 2025-01-17 12:01:11 -05:00
Jason Wen ab8dd45cda do this instead 2025-01-17 10:57:06 -05:00
Jason Wen 66eb3a2532 wrap them around 2025-01-17 10:47:25 -05:00
Jason Wen 59b68e42f6 don't use deprecated method 2025-01-17 10:29:17 -05:00
Jason Wen 976c9ac9bf typo 2025-01-17 02:40:27 -05:00
Jason Wen c65c8a535c no duplicate 2025-01-17 02:39:51 -05:00
Jason Wen 5e79eb774b Merge branch 'sentry-sp' into master-dev-c3-new 2025-01-17 02:06:22 -05:00
Jason Wen 0735fd5553 Merge branch 'dec-redo' into master-dev-c3-new 2025-01-17 02:06:17 -05:00
Jason Wen 5ad8b46158 cap 2025-01-17 02:04:59 -05:00
Jason Wen 3f4e372c34 remove 2025-01-17 01:55:15 -05:00
Jason Wen 7fde68ecf9 have to do this 2025-01-17 01:48:43 -05:00
Jason Wen df1ef23280 use deprecated 2025-01-17 01:41:54 -05:00
Jason Wen 378eb8a4d2 remove unused imports 2025-01-17 01:39:15 -05:00
rav4kumar 40259cd22a dec: faster ? 2025-01-16 23:25:55 -07:00
Kumar 3f29ccbd99 Update dec.py 2025-01-16 23:25:45 -07:00
Jason Wen 189e883116 no point 2025-01-17 01:23:04 -05:00
rav4kumar 01e06df542 dec: how good is FirstOrderFilter? 2025-01-16 23:16:54 -07:00
rav4kumar b1e8824187 revert smooht lead for now 2025-01-16 23:16:00 -07:00
Jason Wen cb1240846b sentry: log fingerprints and save exceptions 2025-01-17 01:15:22 -05:00
Jason Wen fa6ee806f5 Merge branch 'long-distance-btn-exp-mode' into master-dev-c3-new 2025-01-16 18:04:09 -05:00
Jason Wen fefb6a3a25 Merge branch 'dec-redo' into master-dev-c3-new 2025-01-16 18:04:03 -05:00
Jason Wen 13cb725652 Merge branch 'master-new' into long-distance-btn-exp-mode 2025-01-16 18:03:35 -05:00
Jason Wen b219e07ac1 Merge branch 'master-new' into dec-redo
# Conflicts:
#	selfdrive/car/card.py
2025-01-16 18:03:13 -05:00
Jason Wen 90d38a7968 fix tests 2025-01-16 14:24:27 -05:00
Jason Wen bb83e1fe8f Merge branch 'dec-redo' into master-dev-c3-new 2025-01-16 12:09:28 -05:00
Jason Wen baf0506033 use walrus (needs cleanup) 2025-01-16 12:08:15 -05:00
Jason Wen a3db53044e fix wrong typing and variable name 2025-01-16 12:00:20 -05:00
Jason Wen 8673c31e46 Revert "use walrus for None"
This reverts commit 5f2396d490.
2025-01-16 11:59:13 -05:00
Jason Wen 5f2396d490 use walrus for None 2025-01-16 11:56:07 -05:00
Jason Wen e2ff34417f Merge branch 'dec-redo' into master-dev-c3-new 2025-01-15 15:12:39 -05:00
Jason Wen 4ac4fc855f don't set to exp mode initial if DEC is active 2025-01-15 15:12:13 -05:00
Jason Wen cea20d1945 Merge branch 'long-distance-btn-exp-mode' into master-dev-c3-new 2025-01-15 13:41:45 -05:00
Jason Wen 353aa611e7 Merge branch 'dec-redo' into master-dev-c3-new
# Conflicts:
#	sunnypilot/selfdrive/controls/lib/longitudinal_planner.py
2025-01-15 13:41:22 -05:00
Jason Wen 391a3160a0 no need 2025-01-15 11:00:08 -05:00
Jason Wen 6b4ef00ae6 fix 2025-01-15 10:57:51 -05:00
Jason Wen d937062724 more 2025-01-15 01:51:22 -05:00
Jason Wen f94eeb9780 Revert "explicit type hints"
This reverts commit c205497b
2025-01-15 01:46:31 -05:00
Jason Wen c6474fc3ad move to constants py 2025-01-15 01:45:29 -05:00
Jason Wen d7f0e8dd04 unused 2025-01-15 01:28:15 -05:00
Jason Wen f3d94fc291 Longitudinal: Distance button hold to toggle Chill/Experimental Mode 2025-01-15 01:26:23 -05:00
Jason Wen c205497b15 explicit type hints 2025-01-15 00:18:47 -05:00
Jason Wen 45f3c70596 move around 2025-01-14 21:55:56 -05:00
Jason Wen 21793721cc rename 2025-01-14 21:29:42 -05:00
Jason Wen d01b02b185 more 2025-01-14 20:50:57 -05:00
Jason Wen f4af0aa422 update name 2025-01-14 16:42:41 -05:00
Jason Wen d3ecdbb850 fix dec engagement 2025-01-14 00:23:46 -05:00
Jason Wen 1f39c4ccfb remove to fail test 2025-01-14 00:04:48 -05:00
Jason Wen a56e1e6e69 slight cleanup 2025-01-14 00:01:31 -05:00
Jason Wen e630546250 more logs 2025-01-13 23:57:21 -05:00
Jason Wen 85faddc7af this is why it was never using DEC 2025-01-13 23:46:38 -05:00
Jason Wen 223abdc536 never used 2025-01-13 23:26:07 -05:00
Jason Wen dd12f86804 Merge branch 'master-new' into dec-redo
# Conflicts:
#	common/params.cc
2025-01-13 23:11:06 -05:00
Jason Wen dff2a5796d update name 2025-01-13 11:41:11 -05:00
Jason Wen 70918ccff3 Merge branch 'master-new' into dec-redo 2025-01-13 10:23:12 -05:00
Jason Wen f6ef036158 use internal frame 2025-01-12 18:57:22 -05:00
Jason Wen 67692babdc Revert "pass sm.frame from plannerd"
This reverts commit a8deaa69b8.
2025-01-12 18:55:38 -05:00
Jason Wen ea6cd3429b Revert "fix test"
This reverts commit 635b15f2bc.
2025-01-12 18:55:33 -05:00
Jason Wen 635b15f2bc fix test 2025-01-12 18:54:17 -05:00
Jason Wen b42c060b2e more explicit 2025-01-12 18:37:47 -05:00
Jason Wen 1c1ef06489 more 2025-01-12 18:28:20 -05:00
Jason Wen 1b2586914f more fixes 2025-01-12 18:24:58 -05:00
Jason Wen a8deaa69b8 pass sm.frame from plannerd 2025-01-12 18:20:06 -05:00
Jason Wen c34a21980e fix type hint 2025-01-12 18:13:52 -05:00
rav4kumar 6e86d242cd window time 2025-01-12 16:03:17 -07:00
rav4kumar 7113d4a76a smoother trans 2025-01-12 15:54:50 -07:00
Jason Wen 5074881d6d unused 2025-01-12 17:40:21 -05:00
Jason Wen bf3350b7f2 type hint 2025-01-12 17:38:49 -05:00
Jason Wen c64b679704 sync with stock 2025-01-12 17:16:34 -05:00
Jason Wen f645e2cdb0 check live param 2025-01-12 17:12:31 -05:00
Jason Wen 426d41a0a7 rename 2025-01-12 16:56:57 -05:00
Jason Wen de305a81d5 into their own 2025-01-12 16:52:40 -05:00
Jason Wen e4c29a2c58 stuff 2025-01-12 16:50:16 -05:00
Jason Wen c3fde45000 more cleanup 2025-01-12 16:48:44 -05:00
Jason Wen e7d27f0bb9 move around 2025-01-12 16:46:43 -05:00
Jason Wen 12981e02f7 static method 2025-01-12 16:46:15 -05:00
Jason Wen e1cf216c89 some more 2025-01-12 16:44:54 -05:00
Jason Wen cc507a5cd9 cleanup 2025-01-12 16:40:07 -05:00
rav4kumar 87ca1513f4 had moved to car_state 2025-01-12 14:29:22 -07:00
rav4kumar 1d422ce5cf static 2025-01-12 14:06:50 -07:00
rav4kumar cb04017945 Merge branch 'dec-new-refactored-rebased-no-ui' of https://github.com/sunnypilot/sunnypilot into dec-new-refactored-rebased-no-ui 2025-01-12 13:49:17 -07:00
rav4kumar 7d6c9d1a8c static test 2025-01-12 13:48:08 -07:00
Jason Wen ba6559d32a Merge branch 'master-new' into dec-new-refactored-rebased-no-ui 2025-01-12 15:40:47 -05:00
DevTekVE c0c74e3761 **Refactor DEC module structure for better organization**
Moved DEC-related files from `dec` to `lib` for improved clarity and consistency within the project structure. Updated all relevant import paths to reflect the new locations. Ensured functionality remains unaffected with these changes.
2025-01-12 21:03:38 +01:00
DevTekVE 898f5b89ed Refactor DEC into a dedicated longitudinal planner class
Move Dynamic Experimental Control (DEC) logic to a new `DecLongitudinalPlanner` class for better modularity and maintainability. This simplifies the `LongitudinalPlanner` by delegating DEC-specific behavior and consolidates related methods into a single file. Additionally, redundant code was removed to improve readability and reduce complexity.
2025-01-12 20:51:35 +01:00
DevTekVE f861e8d678 Format 2025-01-12 16:40:43 +01:00
DevTekVE fd6ec85e20 Refactor MpcSource definition and update references.
Moved MpcSource enum into LongitudinalPlanSP for better encapsulation. Updated references in helpers.py to use the new path. This change improves code organization and maintains functionality.
2025-01-12 16:40:20 +01:00
DevTekVE 4a46bccc20 rebase fix 2025-01-12 16:33:23 +01:00
DevTekVE 73e658bf8c Formatting 2025-01-12 16:33:23 +01:00
DevTekVE ec25ca070a Format 2025-01-12 16:33:23 +01:00
DevTekVE 84b6af094f Add missing import for messaging in helpers.py
The `messaging` module was added to resolve potential issues with undefined references. This change ensures all required imports are present, improving the reliability and maintainability of the code.
2025-01-12 16:33:23 +01:00
DevTekVE 55b6eae92e Refactor and modularize DynamicExperimentalController logic
Moved DynamicExperimentalController logic and helper functions to a dedicated module for better readability and maintainability. Simplified longitudinal planner logic by introducing reusable methods to manage MPC mode and longitudinal plan publishing. Adjusted file structure for dynamic controller-related components and updated relevant imports.
2025-01-12 16:33:22 +01:00
DevTekVE 760e7e847a new line... 2025-01-12 16:33:22 +01:00
DevTekVE 4b64f85f85 Replace unittest with pytest for dynamic controller tests
Migrated dynamic controller tests from unittest to pytest for improved readability and maintainability. Refactored mock setup using pytest fixtures and monkeypatching while preserving test coverage.
2025-01-12 16:33:22 +01:00
DevTekVE 8dd750fd83 Disabling unittest file to allow checks on the pipeline to succeed.
Pending to remove this, but leaving it to validate the move to pytest is okay before merging
2025-01-12 16:33:21 +01:00
DevTekVE 5e62ccad12 Integrate radar parameter into dynamic controller's pytest tests
Added a `has_radar` parameter to the test functions in the dynamic controller's pytest file. This allows each function to run both with and without radar inputs, thus enhancing the coverage of our test cases.
2025-01-12 16:33:21 +01:00
DevTekVE 2fb0545344 Migrated to pytest using claude 2025-01-12 16:33:21 +01:00
DevTekVE 684431e3f6 Refactor test indentation for dynamic controller tests
Adjust indentation and formatting in test_dynamic_controller.py to ensure consistency and readability. This change does not alter functionality but improves the maintainability of the test code.
2025-01-12 16:33:21 +01:00
DevTekVE ba9fbd52d7 Refactor test_dynamic_controller and fix formatting issues
Added a new import for STOP_AND_GO_FRAME and corrected a float initialization for v_ego in MockCarState. Also fixed indentation in the test_standstill_detection method for consistency.
2025-01-12 16:33:20 +01:00
rav4kumar 1dfaf347f8 unitee testt 2025-01-12 16:33:20 +01:00
rav4kumar 91922fb9b6 fix static test 2025-01-12 16:33:20 +01:00
rav4kumar c4ed5a4617 ff 2025-01-12 16:33:20 +01:00
rav4kumar 90435f0a92 fix static test 2025-01-12 16:33:19 +01:00
Kumar 3c434e78e2 Update sunnypilot/selfdrive/controls/lib/dynamic_experimental_controller.py
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-01-12 16:33:19 +01:00
Kumar 75f6f73798 Update sunnypilot/selfdrive/controls/lib/dynamic_experimental_controller.py
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-01-12 16:33:19 +01:00
rav4kumar c5524c6d42 init dec 2025-01-12 16:33:19 +01:00
114 changed files with 2360 additions and 3864 deletions
-1
View File
@@ -1,3 +1,2 @@
Wen
REGIST
PullRequest
@@ -1,162 +0,0 @@
name: Nightly Branch Reset and PR Squash
env:
DEFAULT_SOURCE_BRANCH: "master-new"
DEFAULT_TARGET_BRANCH: "nightly"
PR_LABEL: "dev-c3"
on:
workflow_dispatch:
inputs:
source_branch:
description: 'Source branch to reset from'
required: true
default: 'master-new'
type: string
target_branch:
description: 'Target branch to reset and squash into'
required: true
default: 'master-dev-c3-new'
type: string
# schedule:
# - cron: '0 0 * * *' # Run at midnight UTC for nightly
jobs:
reset-and-squash:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch all history for all branches
token: ${{ secrets.GITHUB_TOKEN }}
- name: Configure Git
run: |
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install PyGithub
- name: Check branches exist
run: |
# Check if source branch exists
if ! git ls-remote --heads origin ${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }} | grep -q "${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}"; then
echo "Source branch ${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }} does not exist!"
exit 1
fi
# Make sure we have the latest source branch
git fetch origin ${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}
# Check if target branch exists
if ! git ls-remote --heads origin ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} | grep -q "${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}"; then
echo "Target branch ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} does not exist, creating it from ${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}"
git checkout -b ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} origin/${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}
git push origin ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}
else
# Fetch target branch if it exists
git fetch origin ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}
fi
- name: Reset target branch
run: |
echo "Resetting ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} to match ${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}"
# Delete if exists and recreate pointing to source
git branch -D ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} || true
git branch ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} origin/${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}
- name: Get PRs to squash
id: get-prs
run: |
# Use GitHub API to get PRs with specific label, ordered by creation date
PR_LIST=$(gh api graphql -f query='
query($label:String!) {
search(query: $label, type:ISSUE, first:100) {
nodes {
... on PullRequest {
number
headRefName
title
createdAt
commits(last: 1) {
nodes {
commit {
statusCheckRollup {
state
}
}
}
}
}
}
}
}' -F label="is:pr is:open label:${PR_LABEL} sort:created-asc")
echo "PR_LIST=${PR_LIST}" >> $GITHUB_OUTPUT
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Process PRs
run: |
python3 ${{ github.workspace }}/release/ci/squash_and_merge_prs.py \
--pr-data '${{ steps.get-prs.outputs.PR_LIST }}' \
--target-branch ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} \
--squash-script-path '${{ github.workspace }}/release/ci/squash_and_merge.py'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Push changes if there are diffs
id: push-changes # Add an id so we can reference this step
run: |
TARGET_BRANCH="${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}"
# Fetch the latest from remote
git fetch origin $TARGET_BRANCH
# Check for diffs between local and remote
if git diff $TARGET_BRANCH origin/$TARGET_BRANCH --quiet; then
echo "No changes to push - local and remote branches are identical"
echo "has_changes=false" >> $GITHUB_OUTPUT
exit 0
fi
# If we get here, there are diffs, so push
if ! git push origin $TARGET_BRANCH --force; then
echo "Failed to push changes to $TARGET_BRANCH"
exit 1
fi
echo "Branch $TARGET_BRANCH has been reset and updated with squashed PRs"
echo "has_changes=true" >> $GITHUB_OUTPUT
- name: Trigger and wait for selfdrive tests
if: steps.push-changes.outputs.has_changes == 'true'
run: |
echo "Triggering selfdrive tests..."
gh workflow run selfdrive_tests.yaml --ref "${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}"
echo "Sleeping for 120s to give plenty of time for the action to start and then we wait"
sleep 120
echo "Getting latest run ID..."
RUN_ID=$(gh run list --workflow=selfdrive_tests.yaml --branch="${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}" --limit=1 --json databaseId --jq '.[0].databaseId')
echo "Watching run ID: $RUN_ID"
gh run watch "$RUN_ID"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Trigger prebuilt workflow
if: success() && steps.push-changes.outputs.has_changes == 'true'
run: |
gh workflow run sunnypilot-build-prebuilt.yaml --ref "${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+1 -1
View File
@@ -86,7 +86,7 @@ jobs:
run: >-
sudo apt-get install -y imagemagick
scenes="homescreen settings_device settings_network settings_network_advanced settings_software settings_sunnylink settings_toggles settings_sunnypilot settings_sunnypilot_mads settings_trips settings_developer offroad_alert update_available prime onroad onroad_disengaged onroad_override onroad_sidebar onroad_wide onroad_wide_sidebar onroad_alert_small onroad_alert_mid onroad_alert_full driver_camera body keyboard keyboard_uppercase"
scenes="homescreen settings_device settings_software settings_sunnylink settings_toggles settings_sunnypilot settings_sunnypilot_mads settings_trips settings_developer offroad_alert update_available prime onroad onroad_disengaged onroad_override onroad_sidebar onroad_wide onroad_wide_sidebar onroad_alert_small onroad_alert_mid onroad_alert_full driver_camera body keyboard keyboard_uppercase"
A=($scenes)
DIFF=""
+18 -52
View File
@@ -10,23 +10,23 @@ $Cxx.namespace("cereal");
# DO rename the structs
# DON'T change the identifier (e.g. @0x81c2f05a394cf4af)
struct ModularAssistiveDrivingSystem {
state @0 :ModularAssistiveDrivingSystemState;
enabled @1 :Bool;
active @2 :Bool;
available @3 :Bool;
enum ModularAssistiveDrivingSystemState {
disabled @0;
paused @1;
enabled @2;
softDisabling @3;
overriding @4;
}
}
struct SelfdriveStateSP @0x81c2f05a394cf4af {
mads @0 :ModularAssistiveDrivingSystem;
struct ModularAssistiveDrivingSystem {
state @0 :ModularAssistiveDrivingSystemState;
enabled @1 :Bool;
active @2 :Bool;
available @3 :Bool;
enum ModularAssistiveDrivingSystemState {
disabled @0;
paused @1;
enabled @2;
softDisabling @3;
overriding @4;
}
}
}
struct ModelManagerSP @0xaedffd8f31e7b55d {
@@ -81,7 +81,6 @@ struct ModelManagerSP @0xaedffd8f31e7b55d {
generation @5 :UInt32;
environment @6 :Text;
runner @7 :Runner;
is20hz @8 :Bool;
}
}
@@ -100,46 +99,13 @@ struct LongitudinalPlanSP @0xf35cc4560bbf6ec2 {
}
}
struct OnroadEventSP @0xda96579883444c35 {
name @0 :EventName;
# event types
enable @1 :Bool;
noEntry @2 :Bool;
warning @3 :Bool; # alerts presented only when enabled or soft disabling
userDisable @4 :Bool;
softDisable @5 :Bool;
immediateDisable @6 :Bool;
preEnable @7 :Bool;
permanent @8 :Bool; # alerts presented regardless of openpilot state
overrideLateral @10 :Bool;
overrideLongitudinal @9 :Bool;
enum EventName {
lkasEnable @0;
lkasDisable @1;
manualSteeringRequired @2;
manualLongitudinalRequired @3;
silentLkasEnable @4;
silentLkasDisable @5;
silentBrakeHold @6;
silentWrongGear @7;
silentReverseGear @8;
silentDoorOpen @9;
silentSeatbeltNotLatched @10;
silentParkBrake @11;
controlsMismatchLateral @12;
hyundaiRadarTracksConfirmed @13;
experimentalModeSwitched @14;
}
struct CustomReserved3 @0xda96579883444c35 {
}
struct CarParamsSP @0x80ae746ee2596b11 {
flags @0 :UInt32; # flags for car specific quirks in sunnypilot
struct CustomReserved4 @0x80ae746ee2596b11 {
}
struct CarControlSP @0xa5cd762cd951a455 {
mads @0 :ModularAssistiveDrivingSystem;
struct CustomReserved5 @0xa5cd762cd951a455 {
}
struct CustomReserved6 @0xf98d843bfd7004a3 {
+79 -4
View File
@@ -125,6 +125,81 @@ struct OnroadEvent @0xc4fa6047f024e718 {
espActive @90;
personalityChanged @91;
aeb @92;
eventReserved93 @93;
eventReserved94 @94;
eventReserved95 @95;
eventReserved96 @96;
eventReserved97 @97;
eventReserved98 @98;
eventReserved99 @99;
eventReserved100 @100;
eventReserved101 @101;
eventReserved102 @102;
eventReserved103 @103;
eventReserved104 @104;
eventReserved105 @105;
eventReserved106 @106;
eventReserved107 @107;
eventReserved108 @108;
eventReserved109 @109;
eventReserved110 @110;
eventReserved111 @111;
eventReserved112 @112;
eventReserved113 @113;
eventReserved114 @114;
eventReserved115 @115;
eventReserved116 @116;
eventReserved117 @117;
eventReserved118 @118;
eventReserved119 @119;
eventReserved120 @120;
eventReserved121 @121;
eventReserved122 @122;
eventReserved123 @123;
eventReserved124 @124;
eventReserved125 @125;
eventReserved126 @126;
eventReserved127 @127;
eventReserved128 @128;
eventReserved129 @129;
eventReserved130 @130;
eventReserved131 @131;
eventReserved132 @132;
eventReserved133 @133;
eventReserved134 @134;
eventReserved135 @135;
eventReserved136 @136;
eventReserved137 @137;
eventReserved138 @138;
eventReserved139 @139;
eventReserved140 @140;
eventReserved141 @141;
eventReserved142 @142;
eventReserved143 @143;
eventReserved144 @144;
eventReserved145 @145;
eventReserved146 @146;
eventReserved147 @147;
eventReserved148 @148;
eventReserved149 @149;
eventReserved150 @150;
# sunnypilot
lkasEnable @151;
lkasDisable @152;
manualSteeringRequired @153;
manualLongitudinalRequired @154;
silentLkasEnable @155;
silentLkasDisable @156;
silentBrakeHold @157;
silentWrongGear @158;
silentReverseGear @159;
silentDoorOpen @160;
silentSeatbeltNotLatched @161;
silentParkBrake @162;
controlsMismatchLateral @163;
hyundaiRadarTracksConfirmed @164;
experimentalModeSwitched @165;
soundsUnavailableDEPRECATED @47;
}
@@ -590,6 +665,7 @@ struct PandaState @0xa7649e2575e4591e {
# safety stuff
controlsAllowed @3 :Bool;
controlsAllowedLat @5 :Bool;
safetyRxInvalid @19 :UInt32;
safetyTxBlocked @24 :UInt32;
safetyModel @14 :Car.CarParams.SafetyModel;
@@ -697,7 +773,6 @@ struct PandaState @0xa7649e2575e4591e {
}
gasInterceptorDetectedDEPRECATED @4 :Bool;
startedSignalDetectedDEPRECATED @5 :Bool;
hasGpsDEPRECATED @6 :Bool;
gmlanSendErrsDEPRECATED @9 :UInt32;
fanSpeedRpmDEPRECATED @11 :UInt16;
@@ -2568,9 +2643,9 @@ struct Event {
selfdriveStateSP @107 :Custom.SelfdriveStateSP;
modelManagerSP @108 :Custom.ModelManagerSP;
longitudinalPlanSP @109 :Custom.LongitudinalPlanSP;
onroadEventsSP @110 :List(Custom.OnroadEventSP);
carParamsSP @111 :Custom.CarParamsSP;
carControlSP @112 :Custom.CarControlSP;
customReserved3 @110 :Custom.CustomReserved3;
customReserved4 @111 :Custom.CustomReserved4;
customReserved5 @112 :Custom.CustomReserved5;
customReserved6 @113 :Custom.CustomReserved6;
customReserved7 @114 :Custom.CustomReserved7;
customReserved8 @115 :Custom.CustomReserved8;
-3
View File
@@ -78,9 +78,6 @@ _services: dict[str, tuple] = {
"modelManagerSP": (False, 1., 1),
"selfdriveStateSP": (True, 100., 10),
"longitudinalPlanSP": (True, 20., 10),
"onroadEventsSP": (True, 1., 1),
"carParamsSP": (True, 0.02, 1),
"carControlSP": (True, 100., 10),
# debug
"uiDebug": (True, 0., 1),
-3
View File
@@ -8,7 +8,6 @@ import uuid
import socket
import logging
import traceback
import numpy as np
from threading import local
from collections import OrderedDict
from contextlib import contextmanager
@@ -16,8 +15,6 @@ from contextlib import contextmanager
LOG_TIMESTAMPS = "LOG_TIMESTAMPS" in os.environ
def json_handler(obj):
if isinstance(obj, np.bool_):
return bool(obj)
# if isinstance(obj, (datetime.date, datetime.time)):
# return obj.isoformat()
return repr(obj)
-6
View File
@@ -89,7 +89,6 @@ private:
std::unordered_map<std::string, uint32_t> keys = {
{"AccessToken", CLEAR_ON_MANAGER_START | DONT_LOG},
{"AdbEnabled", PERSISTENT},
{"AlwaysOnDM", PERSISTENT},
{"ApiCache_Device", PERSISTENT},
{"AssistNowToken", PERSISTENT},
@@ -203,13 +202,8 @@ std::unordered_map<std::string, uint32_t> keys = {
// --- sunnypilot params --- //
{"ApiCache_DriveStats", PERSISTENT},
{"CarParamsSP", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"CarParamsSPCache", CLEAR_ON_MANAGER_START},
{"CarParamsSPPersistent", PERSISTENT},
{"EnableGithubRunner", PERSISTENT | BACKUP},
{"ModelRunnerTypeCache", CLEAR_ON_ONROAD_TRANSITION},
{"OffroadMode", CLEAR_ON_MANAGER_START},
{"OffroadMode_Status", CLEAR_ON_MANAGER_START},
// MADS params
{"Mads", PERSISTENT | BACKUP},
+3 -3
View File
@@ -10,7 +10,7 @@ A supported vehicle is one that just works when you install a comma device. All
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|Acura|ILX 2016-19|AcuraWatch Plus|openpilot|26 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Acura&model=ILX 2016-19">Buy Here</a></sub></details>||
|Acura|RDX 2016-18|AcuraWatch Plus|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Acura&model=RDX 2016-18">Buy Here</a></sub></details>||
|Acura|RDX 2019-21|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Acura&model=RDX 2019-21">Buy Here</a></sub></details>||
|Acura|RDX 2019-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Acura&model=RDX 2019-22">Buy Here</a></sub></details>||
|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=A3 2014-19">Buy Here</a></sub></details>||
|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=A3 Sportback e-tron 2017-18">Buy Here</a></sub></details>||
|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=Q2 2018">Buy Here</a></sub></details>||
@@ -128,7 +128,7 @@ A supported vehicle is one that just works when you install a comma device. All
|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Jeep&model=Grand Cherokee 2019-21">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=jBe4lWnRSu4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Kia|Carnival 2022-24[<sup>5</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Carnival 2022-24">Buy Here</a></sub></details>||
|Kia|Carnival (China only) 2023[<sup>5</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Carnival (China only) 2023">Buy Here</a></sub></details>||
|Kia|Ceed 2019-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Ceed 2019-21">Buy Here</a></sub></details>||
|Kia|Ceed 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Ceed 2019">Buy Here</a></sub></details>||
|Kia|EV6 (Southeast Asia only) 2022-24[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=EV6 (Southeast Asia only) 2022-24">Buy Here</a></sub></details>||
|Kia|EV6 (with HDA II) 2022-24[<sup>5</sup>](#footnotes)|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=EV6 (with HDA II) 2022-24">Buy Here</a></sub></details>||
|Kia|EV6 (without HDA II) 2022-24[<sup>5</sup>](#footnotes)|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=EV6 (without HDA II) 2022-24">Buy Here</a></sub></details>||
@@ -260,7 +260,7 @@ A supported vehicle is one that just works when you install a comma device. All
|Toyota|RAV4 Hybrid 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 2017-18">Buy Here</a></sub></details>|<a href="https://youtu.be/LhT5VzJVfNI?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 2019-21">Buy Here</a></sub></details>||
|Toyota|RAV4 Hybrid 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 2022">Buy Here</a></sub></details>|<a href="https://youtu.be/U0nH9cnrFB0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|RAV4 Hybrid 2023-25|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 2023-25">Buy Here</a></sub></details>|<a href="https://youtu.be/4eIsEq4L4Ng" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|RAV4 Hybrid 2023-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 2023-24">Buy Here</a></sub></details>||
|Toyota|Sienna 2018-20|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Sienna 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=q1UPOo4Sh68" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Arteon 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Arteon 2018-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Arteon eHybrid 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Arteon eHybrid 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
-9
View File
@@ -63,12 +63,3 @@ A good pull request has all of the following:
* Connect your device to Wi-Fi regularly, so that we can pull data for training better driving models.
* Run the `nightly` branch and report issues. This branch is like `master` but it's built just like a release.
* Annotate images in the [comma10k dataset](https://github.com/commaai/comma10k).
## Contributing Training Data
### A guide for forks
In order for your fork's data to be eligible for the training set:
* **Your cereal messaging structs must be [compatible](../cereal#custom-forks)**
* **The definitions of all the stock messaging structs must not change**: Do not change how any of the fields are set, including everything from `selfdriveState.enabled` to `carState.steeringAngleDeg`. Instead, create your own structs and set them however you'd like.
* **Do not include cars that are not supported in upstream platforms**: Instead, create new opendbc platforms for cars that you'd like to support outside of upstream, even if it's just a trim-level difference.
+1 -1
View File
@@ -7,7 +7,7 @@ export OPENBLAS_NUM_THREADS=1
export VECLIB_MAXIMUM_THREADS=1
if [ -z "$AGNOS_VERSION" ]; then
export AGNOS_VERSION="11.6"
export AGNOS_VERSION="11.4"
fi
export STAGING_ROOT="/data/safe_staging"
+1 -1
Submodule panda updated: 4ca963345a...d3252abcc4
+1 -1
View File
@@ -165,7 +165,7 @@ testpaths = [
[tool.codespell]
quiet-level = 3
# if you've got a short variable name that's getting flagged, add it here
ignore-words-list = "bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints,whit,indexIn,ws,uint,grey,deque,stdio,amin,BA,LITE,atEnd,UIs,errorString,arange,FocusIn,od,tim,relA,hist,copyable,jupyter,thead,TGE,abl"
ignore-words-list = "bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints,whit,indexIn,ws,uint,grey,deque,stdio,amin,BA,LITE,atEnd,UIs,errorString,arange,FocusIn,od,tim,relA,hist,copyable,jupyter,thead"
builtin = "clear,rare,informal,code,names,en-GB_to_en-US"
skip = "./third_party/*, ./tinygrad/*, ./tinygrad_repo/*, ./msgq/*, ./panda/*, ./opendbc/*, ./opendbc_repo/*, ./rednose/*, ./rednose_repo/*, ./teleoprtc/*, ./teleoprtc_repo/*, *.ts, uv.lock, *.onnx, ./cereal/gen/*, */c_generated_code/*"
+6 -6
View File
@@ -117,7 +117,7 @@ def workspace_manager(original_branch: str):
if temp_branch:
run_command(f"git branch -D {temp_branch}")
print("\nOperation interrupted, but changes were already restored.")
sys.exit(3)
sys.exit(1)
# First, switch back to original branch
current = get_current_branch()
@@ -139,12 +139,12 @@ def workspace_manager(original_branch: str):
if signum:
print("\nOperation interrupted. Cleaned up and restored original state.")
sys.exit(4)
sys.exit(1)
except Exception as e:
print(f"Error during cleanup: {e}")
if signum:
sys.exit(5)
sys.exit(1)
try:
# Set up signal handlers
@@ -275,7 +275,7 @@ def squash_and_merge(source_branch: str, target_branch: str, manual_title: str |
return False
print(f"Attempting to merge changes from {temp_branch}...")
code, _, error = run_command(f"git rebase {temp_branch}")
code, _, error = run_command(f"git merge {temp_branch}")
if code != 0:
print(f"\nMerge failed with error: {error}")
@@ -344,7 +344,7 @@ def main():
parser.add_argument('--push', action='store_true',
help='Push changes to remote after squashing')
args, unknown = parser.parse_known_args()
args = parser.parse_args()
# Determine source branch early
source_branch = args.source
@@ -354,7 +354,7 @@ def main():
sys.exit(1)
if not squash_and_merge(source_branch, args.target, args.title, args.backup, args.push):
sys.exit(2)
sys.exit(1)
if __name__ == "__main__":
-163
View File
@@ -1,163 +0,0 @@
#!/usr/bin/env python3
import subprocess
import sys
import os
import argparse
import json
from datetime import datetime
def setup_argument_parser():
parser = argparse.ArgumentParser(description='Process and squash GitHub PRs')
parser.add_argument('--pr-data', type=str, help='PR data in JSON format')
parser.add_argument('--source-branch', type=str, default='master-new',
help='Source branch for merging')
parser.add_argument('--target-branch', type=str, default='master-dev-c3-new-test',
help='Target branch for merging')
parser.add_argument('--squash-script-path', type=str, required=True,
help='Path to the squash_and_merge.py script')
return parser
def validate_squash_script(script_path):
if not os.path.isfile(script_path):
raise FileNotFoundError(f"Squash script not found at: {script_path}")
if not os.access(script_path, os.X_OK):
raise PermissionError(f"Squash script is not executable: {script_path}")
def sort_prs_by_creation(pr_data):
"""Sort PRs by creation date"""
nodes = (pr_data.get('data', {}).get('search', {}).get('nodes', []))
return sorted(
nodes,
key=lambda x: datetime.fromisoformat(x.get('createdAt', '').replace('Z', '+00:00'))
)
def add_pr_comment(pr_number, comment):
"""Add a comment to a PR using gh cli"""
try:
subprocess.run(
['gh', 'pr', 'comment', str(pr_number), '--body', comment],
check=True,
capture_output=True,
text=True
)
except subprocess.CalledProcessError as e:
print(f"Failed to add comment to PR #{pr_number}: {e.stderr}")
def validate_pr(pr):
"""Validate a PR and return (is_valid, skip_reason)"""
pr_number = pr.get('number', 'UNKNOWN')
branch = pr.get('headRefName', '')
if not branch:
return False, f"Missing branch name for PR #{pr_number}"
# Check if checks have passed
commits = pr.get('commits', {}).get('nodes', [])
if not commits:
return False, "No commit data found"
status = commits[0].get('commit', {}).get('statusCheckRollup', {})
if not status or status.get('state') != 'SUCCESS':
return False, "Not all checks have passed"
# Check for merge conflicts
merge_status = subprocess.run(['gh', 'pr', 'view', str(pr_number), '--json', 'mergeable,mergeStateStatus'], capture_output=True, text=True)
merge_data = json.loads(merge_status.stdout)
if not merge_data.get('mergeable'):
return False, "Merge conflicts detected"
if (mergeStateStatus := merge_data.get('mergeStateStatus')) == "BEHIND":
return False, f"Branch is `{mergeStateStatus}`"
return True, None
def process_pr(pr_data, source_branch, target_branch, squash_script_path):
try:
nodes = sort_prs_by_creation(pr_data)
if not nodes:
print("No PRs to squash")
return 0
print(f"Deleting target branch {target_branch}")
subprocess.run(['git', 'branch', '-D', target_branch], check=False)
subprocess.run(['git', 'branch', target_branch, f'origin/{source_branch}'], check=True)
success_count = 0
for pr in nodes:
pr_number = pr.get('number', 'UNKNOWN')
branch = pr.get('headRefName', '')
title = pr.get('title', '')
is_valid, skip_reason = validate_pr(pr)
if not is_valid:
print(f"Warning: {skip_reason} for PR #{pr_number}, skipping")
add_pr_comment(pr_number, f"⚠️ This PR was skipped in the automated `{target_branch}` squash because {skip_reason}.")
continue
try:
# Fetch PR branch
subprocess.run(['git', 'fetch', 'origin', branch], check=True)
# Delete branch if it exists (ignore errors if it doesn't)
subprocess.run(['git', 'branch', '-D', branch], check=False)
# Create new branch pointing to origin's branch
subprocess.run(['git', 'branch', branch, f'origin/{branch}'], check=True)
# Run squash script
subprocess.run([
squash_script_path,
'--target', target_branch,
'--source', branch,
'--title', f"{title} (#{pr_number})",
], check=True)
print(f"Successfully processed PR #{pr_number}")
success_count += 1
except subprocess.CalledProcessError as e:
print(f"Error processing PR #{pr_number}:")
print(f"Command failed with exit code {e.returncode}")
error_output = getattr(e, 'stderr', 'No error output available')
print(f"Error output: {error_output}")
add_pr_comment(pr_number, f"⚠️ Error during automated {target_branch} squash:\n```\n{error_output}\n```")
continue
except Exception as e:
print(f"Unexpected error processing PR #{pr_number}: {str(e)}")
continue
return success_count
except Exception as e:
import traceback
print(f"Error in process_pr: {str(e)}")
print("Full traceback:")
print(traceback.format_exc())
return 0
def main():
parser = setup_argument_parser()
try:
args = parser.parse_args()
validate_squash_script(args.squash_script_path)
pr_data_json = json.loads(args.pr_data)
# Process the PRs
success_count = process_pr(pr_data_json, args.source_branch, args.target_branch, args.squash_script_path)
print(f"Successfully processed {success_count} PRs")
except Exception as e:
print(f"Fatal error: {str(e)}", file=sys.stderr)
return 1
return 0
if __name__ == "__main__":
sys.exit(main())
+12 -31
View File
@@ -5,7 +5,7 @@ import threading
import cereal.messaging as messaging
from cereal import car, log, custom
from cereal import car, log
from panda import ALTERNATIVE_EXPERIENCE
@@ -21,7 +21,6 @@ from opendbc.car.interfaces import CarInterfaceBase, RadarInterfaceBase
from openpilot.selfdrive.pandad import can_capnp_to_list, can_list_to_can_capnp
from openpilot.selfdrive.car.cruise import VCruiseHelper
from openpilot.selfdrive.car.car_specific import MockCarState
from openpilot.selfdrive.car.helpers import convert_carControlSP, convert_to_capnp
from openpilot.sunnypilot.mads.mads import MadsParams
from openpilot.sunnypilot.selfdrive.car import interfaces
@@ -67,13 +66,11 @@ class Car:
CI: CarInterfaceBase
RI: RadarInterfaceBase
CP: car.CarParams
CP_SP: structs.CarParamsSP
CP_SP_capnp: custom.CarParamsSP
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.pm = messaging.PubMaster(['sendcan', 'carState', 'carParams', 'carOutput', 'liveTracks'] + ['carParamsSP'])
self.sm = messaging.SubMaster(['pandaStates', 'carControl', 'onroadEvents'])
self.pm = messaging.PubMaster(['sendcan', 'carState', 'carParams', 'carOutput', 'liveTracks'])
self.can_rcv_cum_timeout_counter = 0
@@ -105,15 +102,14 @@ class Car:
cached_params = _cached_params
self.CI = get_car(*self.can_callbacks, obd_callback(self.params), experimental_long_allowed, num_pandas, cached_params)
interfaces.setup_car_interface_sp(self.CI.CP, self.CI.CP_SP, self.params)
self.RI = get_radar_interface(self.CI.CP, self.CI.CP_SP)
interfaces.setup_car_interface_sp(self.CI.CP, self.params)
self.RI = get_radar_interface(self.CI.CP)
self.CP = self.CI.CP
self.CP_SP = self.CI.CP_SP
# continue onto next fingerprinting step in pandad
self.params.put_bool("FirmwareQueryDone", True)
else:
self.CI, self.CP, self.CP_SP = CI, CI.CP, CI.CP_SP
self.CI, self.CP = CI, CI.CP
self.RI = RI
# set alternative experiences from parameters
@@ -124,7 +120,7 @@ class Car:
# mads
MadsParams().set_alternative_experience(self.CP)
MadsParams().set_car_specific_params(self.CP, self.CP_SP)
MadsParams().set_car_specific_params(self.CP)
# Dynamic Experimental Control
self.dynamic_experimental_control = self.params.get_bool("DynamicExperimentalControl")
@@ -171,14 +167,6 @@ class Car:
self.params.put_nonblocking("CarParamsCache", cp_bytes)
self.params.put_nonblocking("CarParamsPersistent", cp_bytes)
# Write CarParamsSP for controls
# convert to pycapnp representation for caching and logging
self.CP_SP_capnp = convert_to_capnp(self.CP_SP)
cp_sp_bytes = self.CP_SP_capnp.to_bytes()
self.params.put("CarParamsSP", cp_sp_bytes)
self.params.put_nonblocking("CarParamsSPCache", cp_sp_bytes)
self.params.put_nonblocking("CarParamsSPPersistent", cp_sp_bytes)
self.mock_carstate = MockCarState()
self.v_cruise_helper = VCruiseHelper(self.CP)
@@ -257,28 +245,21 @@ class Car:
tracks_msg.liveTracks = RD
self.pm.send('liveTracks', tracks_msg)
# carParamsSP - logged every 50 seconds (> 1 per segment)
if self.sm.frame % int(50. / DT_CTRL) == 0:
cp_sp_send = messaging.new_message('carParamsSP')
cp_sp_send.valid = True
cp_sp_send.carParamsSP = self.CP_SP_capnp
self.pm.send('carParamsSP', cp_sp_send)
def controls_update(self, CS: car.CarState, CC: car.CarControl, CC_SP: custom.CarControlSP):
def controls_update(self, CS: car.CarState, CC: car.CarControl):
"""control update loop, driven by carControl"""
if not self.initialized_prev:
# Initialize CarInterface, once controls are ready
# TODO: this can make us miss at least a few cycles when doing an ECU knockout
self.CI.init(self.CP, self.CP_SP, *self.can_callbacks)
interfaces.initialize_car_interface_sp(self.CP, self.CP_SP, self.params, *self.can_callbacks)
self.CI.init(self.CP, *self.can_callbacks)
interfaces.initialize_car_interface_sp(self.CP, self.params, *self.can_callbacks)
# signal pandad to switch to car safety mode
self.params.put_bool_nonblocking("ControlsReady", True)
if self.sm.all_alive(['carControl']):
# send car controls over can
now_nanos = self.can_log_mono_time if REPLAY else int(time.monotonic() * 1e9)
self.last_actuators_output, can_sends = self.CI.apply(CC, convert_carControlSP(CC_SP), now_nanos)
self.last_actuators_output, can_sends = self.CI.apply(CC, now_nanos)
self.pm.send('sendcan', can_list_to_can_capnp(can_sends, msgtype='sendcan', valid=CS.canValid))
self.CC_prev = CC
@@ -291,7 +272,7 @@ class Car:
initialized = (not any(e.name == EventName.selfdriveInitializing for e in self.sm['onroadEvents']) and
self.sm.seen['onroadEvents'])
if not self.CP.passive and initialized:
self.controls_update(CS, self.sm['carControl'], self.sm['carControlSP'])
self.controls_update(CS, self.sm['carControl'])
self.initialized_prev = initialized
self.CS_prev = CS
-59
View File
@@ -1,59 +0,0 @@
import capnp
from typing import Any
from cereal import custom
from opendbc.car import structs
_FIELDS = '__dataclass_fields__' # copy of dataclasses._FIELDS
def is_dataclass(obj):
"""Similar to dataclasses.is_dataclass without instance type check checking"""
return hasattr(obj, _FIELDS)
def _asdictref_inner(obj) -> dict[str, Any] | Any:
if is_dataclass(obj):
ret = {}
for field in getattr(obj, _FIELDS): # similar to dataclasses.fields()
ret[field] = _asdictref_inner(getattr(obj, field))
return ret
elif isinstance(obj, (tuple, list)):
return type(obj)(_asdictref_inner(v) for v in obj)
else:
return obj
def asdictref(obj) -> dict[str, Any]:
"""
Similar to dataclasses.asdict without recursive type checking and copy.deepcopy
Note that the resulting dict will contain references to the original struct as a result
"""
if not is_dataclass(obj):
raise TypeError("asdictref() should be called on dataclass instances")
return _asdictref_inner(obj)
def convert_to_capnp(struct: structs.CarParamsSP) -> capnp.lib.capnp._DynamicStructBuilder:
struct_dict = asdictref(struct)
if isinstance(struct, structs.CarParamsSP):
struct_capnp = custom.CarParamsSP.new_message(**struct_dict)
else:
raise ValueError(f"Unsupported struct type: {type(struct)}")
return struct_capnp
def convert_carControlSP(struct: capnp.lib.capnp._DynamicStructReader) -> structs.CarControlSP:
# TODO: recursively handle any car struct as needed
def remove_deprecated(s: dict) -> dict:
return {k: v for k, v in s.items() if not k.endswith('DEPRECATED')}
struct_dict = struct.to_dict()
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', {})))
return struct_dataclass
+4 -11
View File
@@ -4,7 +4,7 @@ import hypothesis.strategies as st
from hypothesis import Phase, given, settings
from parameterized import parameterized
from cereal import car, custom
from cereal import car
from opendbc.car import DT_CTRL
from opendbc.car.car_helpers import interfaces
from opendbc.car.structs import CarParams
@@ -12,7 +12,6 @@ from opendbc.car.tests.test_car_interfaces import get_fuzzy_car_interface_args
from opendbc.car.fingerprints import all_known_cars
from opendbc.car.fw_versions import FW_VERSIONS, FW_QUERY_CONFIGS
from opendbc.car.mock.values import CAR as MOCK
from openpilot.selfdrive.car.helpers import convert_carControlSP
from openpilot.selfdrive.controls.lib.latcontrol_angle import LatControlAngle
from openpilot.selfdrive.controls.lib.latcontrol_pid import LatControlPID
from openpilot.selfdrive.controls.lib.latcontrol_torque import LatControlTorque
@@ -41,12 +40,9 @@ class TestCarInterfaces:
car_params = CarInterface.get_params(car_name, args['fingerprints'], args['car_fw'],
experimental_long=args['experimental_long'], docs=False)
car_params_sp = CarInterface.get_params_sp(car_params, car_name, args['fingerprints'], args['car_fw'],
experimental_long=args['experimental_long'], docs=False)
car_params = car_params.as_reader()
car_interface = CarInterface(car_params, car_params_sp, CarController, CarState)
car_interface = CarInterface(car_params, CarController, CarState)
assert car_params
assert car_params_sp
assert car_interface
assert car_params.mass > 1
@@ -73,16 +69,13 @@ class TestCarInterfaces:
assert not math.isnan(tune.torque.friction) and tune.torque.friction > 0
cc_msg = FuzzyGenerator.get_random_msg(data.draw, car.CarControl, real_floats=True)
cc_sp_msg = FuzzyGenerator.get_random_msg(data.draw, custom.CarControlSP, real_floats=True)
# Run car interface
now_nanos = 0
CC = car.CarControl.new_message(**cc_msg)
CC = CC.as_reader()
CC_SP = custom.CarControlSP.new_message(**cc_sp_msg)
CC_SP = convert_carControlSP(CC_SP.as_reader())
for _ in range(10):
car_interface.update([])
car_interface.apply(CC, CC_SP, now_nanos)
car_interface.apply(CC, now_nanos)
now_nanos += DT_CTRL * 1e9 # 10 ms
CC = car.CarControl.new_message(**cc_msg)
@@ -90,7 +83,7 @@ class TestCarInterfaces:
CC = CC.as_reader()
for _ in range(10):
car_interface.update([])
car_interface.apply(CC, CC_SP, now_nanos)
car_interface.apply(CC, now_nanos)
now_nanos += DT_CTRL * 1e9 # 10ms
# Test controller initialization
+10 -15
View File
@@ -1,5 +1,4 @@
import capnp
import copy
import os
import pytest
import random
@@ -159,9 +158,7 @@ class TestCarModelBase(unittest.TestCase):
cls.CarInterface, cls.CarController, cls.CarState, cls.RadarInterface = interfaces[cls.platform]
cls.CP = cls.CarInterface.get_params(cls.platform, cls.fingerprint, car_fw, experimental_long, docs=False)
cls.CP_SP = cls.CarInterface.get_params_sp(cls.CP, cls.platform, cls.fingerprint, car_fw, experimental_long, docs=False)
assert cls.CP
assert cls.CP_SP
assert cls.CP.carFingerprint == cls.platform
os.environ["COMMA_CACHE"] = DEFAULT_DOWNLOAD_CACHE_ROOT
@@ -171,7 +168,7 @@ class TestCarModelBase(unittest.TestCase):
del cls.can_msgs
def setUp(self):
self.CI = self.CarInterface(self.CP.copy(), copy.deepcopy(self.CP_SP), self.CarController, self.CarState)
self.CI = self.CarInterface(self.CP.copy(), self.CarController, self.CarState)
assert self.CI
Params().put_bool("OpenpilotEnabledToggle", self.openpilot_enabled)
@@ -205,11 +202,10 @@ class TestCarModelBase(unittest.TestCase):
can_invalid_cnt = 0
can_valid = False
CC = structs.CarControl().as_reader()
CC_SP = structs.CarControlSP()
for i, msg in enumerate(self.can_msgs):
CS = self.CI.update(can_capnp_to_list((msg.as_builder().to_bytes(),)))
self.CI.apply(CC, CC_SP, msg.logMonoTime)
self.CI.apply(CC, msg.logMonoTime)
if CS.canValid:
can_valid = True
@@ -221,7 +217,7 @@ class TestCarModelBase(unittest.TestCase):
self.assertEqual(can_invalid_cnt, 0)
def test_radar_interface(self):
RI = self.RadarInterface(self.CP, self.CP_SP)
RI = self.RadarInterface(self.CP)
assert RI
# Since OBD port is multiplexed to bus 1 (commonly radar bus) while fingerprinting,
@@ -278,13 +274,13 @@ class TestCarModelBase(unittest.TestCase):
if self.CP.notCar:
self.skipTest("Skipping test for notCar")
def test_car_controller(car_control, car_control_sp):
def test_car_controller(car_control):
now_nanos = 0
msgs_sent = 0
CI = self.CarInterface(self.CP, self.CP_SP, self.CarController, self.CarState)
CI = self.CarInterface(self.CP, self.CarController, self.CarState)
for _ in range(round(10.0 / DT_CTRL)): # make sure we hit the slowest messages
CI.update([])
_, sendcan = CI.apply(car_control, car_control_sp, now_nanos)
_, sendcan = CI.apply(car_control, now_nanos)
now_nanos += DT_CTRL * 1e9
msgs_sent += len(sendcan)
@@ -297,18 +293,17 @@ class TestCarModelBase(unittest.TestCase):
# Make sure we can send all messages while inactive
CC = structs.CarControl()
CC_SP = structs.CarControlSP()
test_car_controller(CC.as_reader(), CC_SP)
test_car_controller(CC.as_reader())
# Test cancel + general messages (controls_allowed=False & cruise_engaged=True)
self.safety.set_cruise_engaged_prev(True)
CC = structs.CarControl(cruiseControl=structs.CarControl.CruiseControl(cancel=True))
test_car_controller(CC.as_reader(), CC_SP)
test_car_controller(CC.as_reader())
# Test resume + general messages (controls_allowed=True & cruise_engaged=True)
self.safety.set_controls_allowed(True)
CC = structs.CarControl(cruiseControl=structs.CarControl.CruiseControl(resume=True))
test_car_controller(CC.as_reader(), CC_SP)
test_car_controller(CC.as_reader())
# Skip stdout/stderr capture with pytest, causes elevated memory usage
@pytest.mark.nocapture
@@ -392,7 +387,7 @@ class TestCarModelBase(unittest.TestCase):
controls_allowed_prev = False
CS_prev = car.CarState.new_message()
checks = defaultdict(int)
selfdrived = SelfdriveD(CP=self.CP, CP_SP=self.CP_SP)
selfdrived = SelfdriveD(CP=self.CP)
selfdrived.initialized = True
for idx, can in enumerate(self.can_msgs):
CS = self.CI.update(can_capnp_to_list((can.as_builder().to_bytes(), ))).as_reader()
+15 -22
View File
@@ -2,7 +2,7 @@
import math
from typing import SupportsFloat
from cereal import car, log, custom
from cereal import car, log
import cereal.messaging as messaging
from openpilot.common.conversions import Conversions as CV
from openpilot.common.params import Params
@@ -19,6 +19,8 @@ from openpilot.selfdrive.controls.lib.longcontrol import LongControl
from openpilot.selfdrive.controls.lib.vehicle_model import VehicleModel
from openpilot.selfdrive.locationd.helpers import PoseCalibrator, Pose
from opendbc.sunnypilot import SunnypilotParamFlags
State = log.SelfdriveState.OpenpilotState
LaneChangeState = log.LaneChangeState
LaneChangeDirection = log.LaneChangeDirection
@@ -32,17 +34,12 @@ class Controls:
self.CP = messaging.log_from_bytes(self.params.get("CarParams", block=True), car.CarParams)
cloudlog.info("controlsd got CarParams")
cloudlog.info("controlsd is waiting for CarParamsSP")
self.CP_SP = messaging.log_from_bytes(self.params.get("CarParamsSP", block=True), custom.CarParamsSP)
cloudlog.info("controlsd got CarParamsSP")
self.CI = get_car_interface(self.CP, self.CP_SP)
self.CI = get_car_interface(self.CP)
self.sm = messaging.SubMaster(['liveParameters', 'liveTorqueParameters', 'modelV2', 'selfdriveState',
'liveCalibration', 'livePose', 'longitudinalPlan', 'carState', 'carOutput',
'driverMonitoringState', 'onroadEvents', 'driverAssistance'] + ['selfdriveStateSP'],
poll='selfdriveState')
self.pm = messaging.PubMaster(['carControl', 'controlsState'] + ['carControlSP'])
'driverMonitoringState', 'onroadEvents', 'driverAssistance'], poll='selfdriveState')
self.pm = messaging.PubMaster(['carControl', 'controlsState'])
self.steer_limited = False
self.desired_curvature = 0.0
@@ -60,6 +57,9 @@ class Controls:
elif self.CP.lateralTuning.which() == 'torque':
self.LaC = LatControlTorque(self.CP, self.CI)
data_services = list(self.sm.data.keys()) + ['selfdriveStateSP']
self.sm = messaging.SubMaster(data_services, poll='selfdriveState')
def update(self):
self.sm.update(15)
if self.sm.updated["liveCalibration"]:
@@ -94,7 +94,9 @@ class Controls:
standstill = abs(CS.vEgo) <= max(self.CP.minSteerSpeed, MIN_LATERAL_CONTROL_SPEED) or CS.standstill
ss_sp = self.sm['selfdriveStateSP']
CC.madsEnabled = ss_sp.mads.enabled
if ss_sp.mads.available:
CC.sunnypilotParams |= SunnypilotParamFlags.ENABLE_MADS.value
_lat_active = ss_sp.mads.active
else:
_lat_active = self.sm['selfdriveState'].active
@@ -137,12 +139,9 @@ class Controls:
cloudlog.error(f"actuators.{p} not finite {actuators.to_dict()}")
setattr(actuators, p, 0.0)
CC_SP = custom.CarControlSP.new_message()
CC_SP.mads = ss_sp.mads
return CC, lac_log
return CC, CC_SP, lac_log
def publish(self, CC, CC_SP, lac_log):
def publish(self, CC, lac_log):
CS = self.sm['carState']
# Orientation and angle rates can be useful for carcontroller
@@ -218,18 +217,12 @@ class Controls:
cc_send.carControl = CC
self.pm.send('carControl', cc_send)
# carControlSP
cc_sp_send = messaging.new_message('carControlSP')
cc_sp_send.valid = CS.canValid
cc_sp_send.carControlSP = CC_SP
self.pm.send('carControlSP', cc_sp_send)
def run(self):
rk = Ratekeeper(100, print_delay_threshold=None)
while True:
self.update()
CC, CC_SP, lac_log = self.state_control()
self.publish(CC, CC_SP, lac_log)
CC, lac_log = self.state_control()
self.publish(CC, lac_log)
rk.monitor_time()
def main():
@@ -19,8 +19,7 @@ class TestLatControl:
def test_saturation(self, car_name, controller):
CarInterface, CarController, CarState, RadarInterface = interfaces[car_name]
CP = CarInterface.get_non_essential_params(car_name)
CP_SP = CarInterface.get_non_essential_params_sp(CP, car_name)
CI = CarInterface(CP, CP_SP, CarController, CarState)
CI = CarInterface(CP, CarController, CarState)
VM = VehicleModel(CP)
controller = controller(CP.as_reader(), CI)
-5
View File
@@ -1,5 +0,0 @@
from pathlib import Path
MODEL_PATH = Path(__file__).parent / 'models/supercombo.onnx'
MODEL_PKL_PATH = Path(__file__).parent / 'models/supercombo_tinygrad.pkl'
METADATA_PATH = Path(__file__).parent / 'models/supercombo_metadata.pkl'
+2 -16
View File
@@ -26,7 +26,6 @@ from openpilot.common.transformations.model import dmonitoringmodel_intrinsics,
from openpilot.common.transformations.camera import _ar_ox_fisheye, _os_fisheye
from openpilot.selfdrive.modeld.models.commonmodel_pyx import CLContext, MonitoringModelFrame
from openpilot.selfdrive.modeld.parse_model_outputs import sigmoid
from openpilot.system import sentry
MODEL_WIDTH, MODEL_HEIGHT = DM_INPUT_SIZE
CALIB_LEN = 3
@@ -38,7 +37,6 @@ SEND_RAW_PRED = os.getenv('SEND_RAW_PRED')
MODEL_PATH = Path(__file__).parent / 'models/dmonitoring_model.onnx'
MODEL_PKL_PATH = Path(__file__).parent / 'models/dmonitoring_model_tinygrad.pkl'
class DriverStateResult(ctypes.Structure):
_fields_ = [
("face_orientation", ctypes.c_float*3),
@@ -57,7 +55,6 @@ class DriverStateResult(ctypes.Structure):
("ready_prob", ctypes.c_float*4),
("not_ready_prob", ctypes.c_float*2)]
class DMonitoringModelResult(ctypes.Structure):
_fields_ = [
("driver_state_lhd", DriverStateResult),
@@ -66,7 +63,6 @@ class DMonitoringModelResult(ctypes.Structure):
("wheel_on_right_prob", ctypes.c_float),
("features", ctypes.c_float*FEATURE_LEN)]
class ModelState:
inputs: dict[str, np.ndarray]
output: np.ndarray
@@ -86,7 +82,7 @@ class ModelState:
else:
self.onnx_cpu_runner = make_onnx_cpu_runner(MODEL_PATH)
def run(self, buf: VisionBuf, calib: np.ndarray, transform: np.ndarray) -> tuple[np.ndarray, float]:
def run(self, buf:VisionBuf, calib:np.ndarray, transform:np.ndarray) -> tuple[np.ndarray, float]:
self.numpy_inputs['calib'][0,:] = calib
t1 = time.perf_counter()
@@ -123,7 +119,6 @@ def fill_driver_state(msg, ds_result: DriverStateResult):
msg.readyProb = [float(sigmoid(x)) for x in ds_result.ready_prob]
msg.notReadyProb = [float(sigmoid(x)) for x in ds_result.not_ready_prob]
def get_driverstate_packet(model_output: np.ndarray, frame_id: int, location_ts: int, execution_time: float, gpu_execution_time: float):
model_result = ctypes.cast(model_output.ctypes.data, ctypes.POINTER(DMonitoringModelResult)).contents
msg = messaging.new_message('driverStateV2', valid=True)
@@ -144,9 +139,6 @@ def main():
setproctitle(PROCESS_NAME)
set_realtime_priority(1)
sentry.set_tag("daemon", PROCESS_NAME)
cloudlog.bind(daemon=PROCESS_NAME)
cl_context = CLContext()
model = ModelState(cl_context)
cloudlog.warning("models loaded, dmonitoringmodeld starting")
@@ -185,10 +177,4 @@ def main():
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
cloudlog.warning(f"child {PROCESS_NAME} got SIGINT")
except Exception:
sentry.capture_exception()
raise
main()
+35 -49
View File
@@ -2,33 +2,13 @@ import os
import capnp
import numpy as np
from cereal import log
from openpilot.selfdrive.modeld.constants import ModelConstants, Plan
from openpilot.selfdrive.controls.lib.drive_helpers import MIN_SPEED
from openpilot.selfdrive.modeld.constants import ModelConstants, Plan, Meta
SEND_RAW_PRED = os.getenv('SEND_RAW_PRED')
ConfidenceClass = log.ModelDataV2.ConfidenceClass
def curv_from_psis(psi_target, psi_rate, vego, delay):
vego = np.clip(vego, MIN_SPEED, np.inf)
curv_from_psi = psi_target / (vego * delay) # epsilon to prevent divide-by-zero
return 2 * curv_from_psi - psi_rate / vego
def get_curvature_from_plan(plan, vego, delay):
psi_target = np.interp(delay, ModelConstants.T_IDXS, plan[:, Plan.T_FROM_CURRENT_EULER][:, 2])
psi_rate = plan[:, Plan.ORIENTATION_RATE][0, 2]
return curv_from_psis(psi_target, psi_rate, vego, delay)
def get_curvature_from_output(output, vego, delay):
if desired_curv := output.get('desired_curvature'): # If the model outputs the desired curvature, use that directly
return float(desired_curv[0, 0])
return float(get_curvature_from_plan(output['plan'][0], vego, delay))
class PublishState:
def __init__(self):
self.disengage_buffer = np.zeros(ModelConstants.CONFIDENCE_BUFFER_LEN*ModelConstants.DISENGAGE_WIDTH, dtype=np.float32)
@@ -79,21 +59,21 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D
net_output_data: dict[str, np.ndarray], v_ego: float, delay: float,
publish_state: PublishState, vipc_frame_id: int, vipc_frame_id_extra: int,
frame_id: int, frame_drop: float, timestamp_eof: int, model_execution_time: float,
valid: bool, model_meta) -> None:
valid: bool) -> None:
frame_age = frame_id - vipc_frame_id if frame_id > vipc_frame_id else 0
frame_drop_perc = frame_drop * 100
extended_msg.valid = valid
base_msg.valid = valid
desired_curvature = float(get_curvature_from_output(net_output_data, v_ego, delay))
driving_model_data = base_msg.drivingModelData
driving_model_data.frameId = vipc_frame_id
driving_model_data.frameIdExtra = vipc_frame_id_extra
driving_model_data.frameDropPerc = frame_drop_perc
driving_model_data.modelExecutionTime = model_execution_time
driving_model_data.action.desiredCurvature = desired_curvature
action = driving_model_data.action
action.desiredCurvature = float(net_output_data['desired_curvature'][0,0])
modelV2 = extended_msg.modelV2
modelV2.frameId = vipc_frame_id
@@ -104,11 +84,16 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D
modelV2.modelExecutionTime = model_execution_time
# plan
fill_xyzt(modelV2.position, ModelConstants.T_IDXS, *net_output_data['plan'][0,:,Plan.POSITION].T, *net_output_data['plan_stds'][0,:,Plan.POSITION].T)
fill_xyzt(modelV2.velocity, ModelConstants.T_IDXS, *net_output_data['plan'][0,:,Plan.VELOCITY].T)
fill_xyzt(modelV2.acceleration, ModelConstants.T_IDXS, *net_output_data['plan'][0,:,Plan.ACCELERATION].T)
fill_xyzt(modelV2.orientation, ModelConstants.T_IDXS, *net_output_data['plan'][0,:,Plan.T_FROM_CURRENT_EULER].T)
fill_xyzt(modelV2.orientationRate, ModelConstants.T_IDXS, *net_output_data['plan'][0,:,Plan.ORIENTATION_RATE].T)
position = modelV2.position
fill_xyzt(position, ModelConstants.T_IDXS, *net_output_data['plan'][0,:,Plan.POSITION].T, *net_output_data['plan_stds'][0,:,Plan.POSITION].T)
velocity = modelV2.velocity
fill_xyzt(velocity, ModelConstants.T_IDXS, *net_output_data['plan'][0,:,Plan.VELOCITY].T)
acceleration = modelV2.acceleration
fill_xyzt(acceleration, ModelConstants.T_IDXS, *net_output_data['plan'][0,:,Plan.ACCELERATION].T)
orientation = modelV2.orientation
fill_xyzt(orientation, ModelConstants.T_IDXS, *net_output_data['plan'][0,:,Plan.T_FROM_CURRENT_EULER].T)
orientation_rate = modelV2.orientationRate
fill_xyzt(orientation_rate, ModelConstants.T_IDXS, *net_output_data['plan'][0,:,Plan.ORIENTATION_RATE].T)
# temporal pose
temporal_pose = modelV2.temporalPose
@@ -118,10 +103,12 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D
temporal_pose.rotStd = net_output_data['plan_stds'][0,0,Plan.ORIENTATION_RATE].tolist()
# poly path
fill_xyz_poly(driving_model_data.path, ModelConstants.POLY_PATH_DEGREE, *net_output_data['plan'][0,:,Plan.POSITION].T)
poly_path = driving_model_data.path
fill_xyz_poly(poly_path, ModelConstants.POLY_PATH_DEGREE, *net_output_data['plan'][0,:,Plan.POSITION].T)
# lateral planning
modelV2.action.desiredCurvature = desired_curvature
action = modelV2.action
action.desiredCurvature = float(net_output_data['desired_curvature'][0,0])
# times at X_IDXS according to model plan
PLAN_T_IDXS = [np.nan] * ModelConstants.IDX_N
@@ -150,7 +137,8 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D
modelV2.laneLineStds = net_output_data['lane_lines_stds'][0,:,0,0].tolist()
modelV2.laneLineProbs = net_output_data['lane_lines_prob'][0,1::2].tolist()
fill_lane_line_meta(driving_model_data.laneLineMeta, modelV2.laneLines, modelV2.laneLineProbs)
lane_line_meta = driving_model_data.laneLineMeta
fill_lane_line_meta(lane_line_meta, modelV2.laneLines, modelV2.laneLineProbs)
# road edges
modelV2.init('roadEdges', 2)
@@ -171,25 +159,23 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D
meta = modelV2.meta
meta.desireState = net_output_data['desire_state'][0].reshape(-1).tolist()
meta.desirePrediction = net_output_data['desire_pred'][0].reshape(-1).tolist()
meta.engagedProb = net_output_data['meta'][0,model_meta.ENGAGED].item()
meta.engagedProb = net_output_data['meta'][0,Meta.ENGAGED].item()
meta.init('disengagePredictions')
disengage_predictions = meta.disengagePredictions
disengage_predictions.t = ModelConstants.META_T_IDXS
disengage_predictions.brakeDisengageProbs = net_output_data['meta'][0,model_meta.BRAKE_DISENGAGE].tolist()
disengage_predictions.gasDisengageProbs = net_output_data['meta'][0,model_meta.GAS_DISENGAGE].tolist()
disengage_predictions.steerOverrideProbs = net_output_data['meta'][0,model_meta.STEER_OVERRIDE].tolist()
disengage_predictions.brake3MetersPerSecondSquaredProbs = net_output_data['meta'][0,model_meta.HARD_BRAKE_3].tolist()
disengage_predictions.brake4MetersPerSecondSquaredProbs = net_output_data['meta'][0,model_meta.HARD_BRAKE_4].tolist()
disengage_predictions.brake5MetersPerSecondSquaredProbs = net_output_data['meta'][0,model_meta.HARD_BRAKE_5].tolist()
if hasattr(model_meta, 'GAS_PRESS') and hasattr(model_meta, 'BRAKE_PRESS'):
disengage_predictions.gasPressProbs = net_output_data['meta'][0,model_meta.GAS_PRESS].tolist()
disengage_predictions.brakePressProbs = net_output_data['meta'][0,model_meta.BRAKE_PRESS].tolist()
disengage_predictions.brakeDisengageProbs = net_output_data['meta'][0,Meta.BRAKE_DISENGAGE].tolist()
disengage_predictions.gasDisengageProbs = net_output_data['meta'][0,Meta.GAS_DISENGAGE].tolist()
disengage_predictions.steerOverrideProbs = net_output_data['meta'][0,Meta.STEER_OVERRIDE].tolist()
disengage_predictions.brake3MetersPerSecondSquaredProbs = net_output_data['meta'][0,Meta.HARD_BRAKE_3].tolist()
disengage_predictions.brake4MetersPerSecondSquaredProbs = net_output_data['meta'][0,Meta.HARD_BRAKE_4].tolist()
disengage_predictions.brake5MetersPerSecondSquaredProbs = net_output_data['meta'][0,Meta.HARD_BRAKE_5].tolist()
#disengage_predictions.gasPressProbs = net_output_data['meta'][0,Meta.GAS_PRESS].tolist()
#disengage_predictions.brakePressProbs = net_output_data['meta'][0,Meta.BRAKE_PRESS].tolist()
publish_state.prev_brake_5ms2_probs[:-1] = publish_state.prev_brake_5ms2_probs[1:]
publish_state.prev_brake_5ms2_probs[-1] = net_output_data['meta'][0,model_meta.HARD_BRAKE_5][0]
publish_state.prev_brake_5ms2_probs[-1] = net_output_data['meta'][0,Meta.HARD_BRAKE_5][0]
publish_state.prev_brake_3ms2_probs[:-1] = publish_state.prev_brake_3ms2_probs[1:]
publish_state.prev_brake_3ms2_probs[-1] = net_output_data['meta'][0,model_meta.HARD_BRAKE_3][0]
publish_state.prev_brake_3ms2_probs[-1] = net_output_data['meta'][0,Meta.HARD_BRAKE_3][0]
hard_brake_predicted = (publish_state.prev_brake_5ms2_probs > ModelConstants.FCW_THRESHOLDS_5MS2).all() and \
(publish_state.prev_brake_3ms2_probs > ModelConstants.FCW_THRESHOLDS_3MS2).all()
meta.hardBrakePredicted = hard_brake_predicted.item()
@@ -197,9 +183,9 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D
# confidence
if vipc_frame_id % (2*ModelConstants.MODEL_FREQ) == 0:
# any disengage prob
brake_disengage_probs = net_output_data['meta'][0,model_meta.BRAKE_DISENGAGE]
gas_disengage_probs = net_output_data['meta'][0,model_meta.GAS_DISENGAGE]
steer_override_probs = net_output_data['meta'][0,model_meta.STEER_OVERRIDE]
brake_disengage_probs = net_output_data['meta'][0,Meta.BRAKE_DISENGAGE]
gas_disengage_probs = net_output_data['meta'][0,Meta.GAS_DISENGAGE]
steer_override_probs = net_output_data['meta'][0,Meta.STEER_OVERRIDE]
any_disengage_probs = 1-((1-brake_disengage_probs)*(1-gas_disengage_probs)*(1-steer_override_probs))
# independent disengage prob for each 2s slice
ind_disengage_probs = np.r_[any_disengage_probs[0], np.diff(any_disengage_probs) / (1 - any_disengage_probs[:-1])]
+65 -63
View File
@@ -1,11 +1,21 @@
#!/usr/bin/env python3
import os
from openpilot.system.hardware import TICI
#
if TICI:
from tinygrad.tensor import Tensor
from tinygrad.dtype import dtypes
from openpilot.selfdrive.modeld.runners.tinygrad_helpers import qcom_tensor_from_opencl_address
os.environ['QCOM'] = '1'
else:
from openpilot.selfdrive.modeld.runners.ort_helpers import make_onnx_cpu_runner
import time
import pickle
import numpy as np
import cereal.messaging as messaging
from cereal import car, log
from pathlib import Path
from setproctitle import setproctitle
from cereal.messaging import PubMaster, SubMaster
from msgq.visionipc import VisionIpcClient, VisionStreamType, VisionBuf
@@ -23,11 +33,13 @@ from openpilot.selfdrive.modeld.fill_model_msg import fill_model_msg, fill_pose_
from openpilot.selfdrive.modeld.constants import ModelConstants
from openpilot.selfdrive.modeld.models.commonmodel_pyx import DrivingModelFrame, CLContext
from openpilot.sunnypilot.modeld_v2.meta_helper import load_meta_constants
from openpilot.sunnypilot.modeld_v2.model_runner import ONNXRunner, TinygradRunner
PROCESS_NAME = "selfdrive.modeld.modeld"
SEND_RAW_PRED = os.getenv('SEND_RAW_PRED')
MODEL_PATH = Path(__file__).parent / 'models/supercombo.onnx'
MODEL_PKL_PATH = Path(__file__).parent / 'models/supercombo_tinygrad.pkl'
METADATA_PATH = Path(__file__).parent / 'models/supercombo_metadata.pkl'
class FrameMeta:
frame_id: int = 0
@@ -45,35 +57,39 @@ class ModelState:
prev_desire: np.ndarray # for tracking the rising edge of the pulse
def __init__(self, context: CLContext):
try:
self.model_runner = TinygradRunner() if TICI else ONNXRunner()
except Exception as e:
cloudlog.exception(f"Failed to initialize model runner: {str(e)}")
buffer_length = 5 if self.model_runner.is_20hz else 2
self.frames = {'input_imgs': DrivingModelFrame(context, buffer_length), 'big_input_imgs': DrivingModelFrame(context, buffer_length)}
self.frames = {'input_imgs': DrivingModelFrame(context), 'big_input_imgs': DrivingModelFrame(context)}
self.prev_desire = np.zeros(ModelConstants.DESIRE_LEN, dtype=np.float32)
if self.model_runner.is_20hz:
self.full_features_20Hz = np.zeros((ModelConstants.FULL_HISTORY_BUFFER_LEN, ModelConstants.FEATURE_LEN), dtype=np.float32)
self.desire_20Hz = np.zeros((ModelConstants.FULL_HISTORY_BUFFER_LEN + 1, ModelConstants.DESIRE_LEN), dtype=np.float32)
# img buffers are managed in openCL transform code
self.numpy_inputs = {}
self.numpy_inputs = {
'desire': np.zeros((1, (ModelConstants.FULL_HISTORY_BUFFER_LEN+1), ModelConstants.DESIRE_LEN), dtype=np.float32),
'traffic_convention': np.zeros((1, ModelConstants.TRAFFIC_CONVENTION_LEN), dtype=np.float32),
'lateral_control_params': np.zeros((1, ModelConstants.LATERAL_CONTROL_PARAMS_LEN), dtype=np.float32),
'prev_desired_curv': np.zeros((1, (ModelConstants.FULL_HISTORY_BUFFER_LEN+1), ModelConstants.PREV_DESIRED_CURV_LEN), dtype=np.float32),
'features_buffer': np.zeros((1, ModelConstants.FULL_HISTORY_BUFFER_LEN, ModelConstants.FEATURE_LEN), dtype=np.float32),
}
for key, shape in self.model_runner.input_shapes.items():
if key not in self.frames: # Managed by opencl
self.numpy_inputs[key] = np.zeros(shape, dtype=np.float32)
with open(METADATA_PATH, 'rb') as f:
model_metadata = pickle.load(f)
self.input_shapes = model_metadata['input_shapes']
self.output_slices = model_metadata['output_slices']
net_output_size = model_metadata['output_shapes']['outputs'][1]
self.output = np.zeros(net_output_size, dtype=np.float32)
self.parser = Parser()
if self.model_runner.is_20hz:
net_output_size = self.model_runner.model_metadata['output_shapes']['outputs'][1]
self.output = np.zeros(net_output_size, dtype=np.float32)
if TICI:
self.tensor_inputs = {k: Tensor(v, device='NPY').realize() for k,v in self.numpy_inputs.items()}
with open(MODEL_PKL_PATH, "rb") as f:
self.model_run = pickle.load(f)
else:
self.onnx_cpu_runner = make_onnx_cpu_runner(MODEL_PATH)
num_elements = self.numpy_inputs['features_buffer'].shape[1]
step_size = int(-100 / num_elements)
self.full_features_20Hz_idxs = np.arange(step_size, step_size * (num_elements + 1), step_size)[::-1]
self.desire_reshape_dims = (self.numpy_inputs['desire'].shape[0], self.numpy_inputs['desire'].shape[1], -1, self.numpy_inputs['desire'].shape[2])
def slice_outputs(self, model_outputs: np.ndarray) -> dict[str, np.ndarray]:
parsed_model_outputs = {k: model_outputs[np.newaxis, v] for k,v in self.output_slices.items()}
if SEND_RAW_PRED:
parsed_model_outputs['raw_pred'] = model_outputs.copy()
return parsed_model_outputs
def run(self, buf: VisionBuf, wbuf: VisionBuf, transform: np.ndarray, transform_wide: np.ndarray,
inputs: dict[str, np.ndarray], prepare_only: bool) -> dict[str, np.ndarray] | None:
@@ -82,53 +98,40 @@ class ModelState:
new_desire = np.where(inputs['desire'] - self.prev_desire > .99, inputs['desire'], 0)
self.prev_desire[:] = inputs['desire']
if self.model_runner.is_20hz:
self.desire_20Hz[:-1] = self.desire_20Hz[1:]
self.desire_20Hz[-1] = new_desire
self.numpy_inputs['desire'][:] = self.desire_20Hz.reshape(self.desire_reshape_dims).max(axis=2)
else:
length = inputs['desire'].shape[0]
self.numpy_inputs['desire'][0, :-1] = self.numpy_inputs['desire'][0, 1:]
self.numpy_inputs['desire'][0, -1, :length] = new_desire[:length]
for key in self.numpy_inputs:
if key in inputs and key not in ['desire']:
self.numpy_inputs[key][:] = inputs[key]
self.numpy_inputs['desire'][0,:-1] = self.numpy_inputs['desire'][0,1:]
self.numpy_inputs['desire'][0,-1] = new_desire
self.numpy_inputs['traffic_convention'][:] = inputs['traffic_convention']
self.numpy_inputs['lateral_control_params'][:] = inputs['lateral_control_params']
imgs_cl = {'input_imgs': self.frames['input_imgs'].prepare(buf, transform.flatten()),
'big_input_imgs': self.frames['big_input_imgs'].prepare(wbuf, transform_wide.flatten())}
# Prepare inputs using the model runner
self.model_runner.prepare_inputs(imgs_cl, self.numpy_inputs, self.frames)
if TICI:
# The imgs tensors are backed by opencl memory, only need init once
for key in imgs_cl:
if key not in self.tensor_inputs:
self.tensor_inputs[key] = qcom_tensor_from_opencl_address(imgs_cl[key].mem_address, self.input_shapes[key], dtype=dtypes.uint8)
else:
for key in imgs_cl:
self.numpy_inputs[key] = self.frames[key].buffer_from_cl(imgs_cl[key]).reshape(self.input_shapes[key]).astype(dtype=np.float32)
if prepare_only:
return None
# Run model inference
self.output = self.model_runner.run_model()
outputs = self.parser.parse_outputs(self.model_runner.slice_outputs(self.output))
if self.model_runner.is_20hz:
self.full_features_20Hz[:-1] = self.full_features_20Hz[1:]
self.full_features_20Hz[-1] = outputs['hidden_state'][0, :]
self.numpy_inputs['features_buffer'][:] = self.full_features_20Hz[self.full_features_20Hz_idxs]
if TICI:
self.output = self.model_run(**self.tensor_inputs).numpy().flatten()
else:
feature_len = outputs['hidden_state'].shape[1]
self.numpy_inputs['features_buffer'][0, :-1] = self.numpy_inputs['features_buffer'][0, 1:]
self.numpy_inputs['features_buffer'][0, -1, :feature_len] = outputs['hidden_state'][0, :feature_len]
self.output = self.onnx_cpu_runner.run(None, self.numpy_inputs)[0].flatten()
if "desired_curvature" in outputs:
input_name_prev = None
outputs = self.parser.parse_outputs(self.slice_outputs(self.output))
if "prev_desired_curvs" in self.numpy_inputs.keys():
input_name_prev = 'prev_desired_curvs'
elif "prev_desired_curv" in self.numpy_inputs.keys():
input_name_prev = 'prev_desired_curv'
self.numpy_inputs['features_buffer'][0,:-1] = self.numpy_inputs['features_buffer'][0,1:]
self.numpy_inputs['features_buffer'][0,-1] = outputs['hidden_state'][0, :]
if input_name_prev is not None:
length = outputs['desired_curvature'][0].size
self.numpy_inputs[input_name_prev][0, :-length, 0] = self.numpy_inputs[input_name_prev][0, length:, 0]
self.numpy_inputs[input_name_prev][0, -length:, 0] = outputs['desired_curvature'][0]
# TODO model only uses last value now
self.numpy_inputs['prev_desired_curv'][0,:-1] = self.numpy_inputs['prev_desired_curv'][0,1:]
self.numpy_inputs['prev_desired_curv'][0,-1,:] = outputs['desired_curvature'][0, :]
return outputs
@@ -239,6 +242,7 @@ def main(demo=False):
is_rhd = sm["driverMonitoringState"].isRHD
frame_id = sm["roadCameraState"].frameId
v_ego = max(sm["carState"].vEgo, 0.)
lateral_control_params = np.array([v_ego, steer_delay], dtype=np.float32)
if sm.updated["liveCalibration"] and sm.seen['roadCameraState'] and sm.seen['deviceState']:
device_from_calib_euler = np.array(sm["liveCalibration"].rpyCalib, dtype=np.float32)
dc = DEVICE_CAMERAS[(str(sm['deviceState'].deviceType), str(sm['roadCameraState'].sensor))]
@@ -269,10 +273,8 @@ def main(demo=False):
inputs:dict[str, np.ndarray] = {
'desire': vec_desire,
'traffic_convention': traffic_convention,
}
if "lateral_control_params" in model.numpy_inputs.keys():
inputs['lateral_control_params'] = np.array([v_ego, steer_delay], dtype=np.float32)
'lateral_control_params': lateral_control_params,
}
mt1 = time.perf_counter()
model_output = model.run(buf_main, buf_extra, model_transform_main, model_transform_extra, inputs, prepare_only)
@@ -285,7 +287,7 @@ def main(demo=False):
posenet_send = messaging.new_message('cameraOdometry')
fill_model_msg(drivingdata_send, modelv2_send, model_output, v_ego, steer_delay,
publish_state, meta_main.frame_id, meta_extra.frame_id, frame_id,
frame_drop_ratio, meta_main.timestamp_eof, model_execution_time, live_calib_seen, load_meta_constants())
frame_drop_ratio, meta_main.timestamp_eof, model_execution_time, live_calib_seen)
desire_state = modelv2_send.modelV2.meta.desireState
l_lane_change_prob = desire_state[log.Desire.laneChangeLeft]
+4 -5
View File
@@ -5,14 +5,13 @@
#include "common/clutil.h"
DrivingModelFrame::DrivingModelFrame(cl_device_id device_id, cl_context context, uint8_t buffer_length) : ModelFrame(device_id, context), buffer_length(buffer_length) {
DrivingModelFrame::DrivingModelFrame(cl_device_id device_id, cl_context context) : ModelFrame(device_id, context) {
input_frames = std::make_unique<uint8_t[]>(buf_size);
input_frames_cl = CL_CHECK_ERR(clCreateBuffer(context, CL_MEM_READ_WRITE, buf_size, NULL, &err));
img_buffer_20hz_cl = CL_CHECK_ERR(clCreateBuffer(context, CL_MEM_READ_WRITE, buffer_length*frame_size_bytes, NULL, &err));
region.origin = (buffer_length - 1) * frame_size_bytes;
img_buffer_20hz_cl = CL_CHECK_ERR(clCreateBuffer(context, CL_MEM_READ_WRITE, 2*frame_size_bytes, NULL, &err));
region.origin = 1 * frame_size_bytes;
region.size = frame_size_bytes;
last_img_cl = CL_CHECK_ERR(clCreateSubBuffer(img_buffer_20hz_cl, CL_MEM_READ_WRITE, CL_BUFFER_CREATE_TYPE_REGION, &region, &err));
// printf("Buffer length: %d, region origin: %lu, region size: %lu\n", buffer_length, region.origin, region.size);
loadyuv_init(&loadyuv, context, device_id, MODEL_WIDTH, MODEL_HEIGHT);
init_transform(device_id, context, MODEL_WIDTH, MODEL_HEIGHT);
@@ -21,7 +20,7 @@ DrivingModelFrame::DrivingModelFrame(cl_device_id device_id, cl_context context,
cl_mem* DrivingModelFrame::prepare(cl_mem yuv_cl, int frame_width, int frame_height, int frame_stride, int frame_uv_offset, const mat3& projection) {
run_transform(yuv_cl, MODEL_WIDTH, MODEL_HEIGHT, frame_width, frame_height, frame_stride, frame_uv_offset, projection);
for (int i = 0; i < (buffer_length - 1); i++) {
for (int i = 0; i < 1; i++) {
CL_CHECK(clEnqueueCopyBuffer(q, img_buffer_20hz_cl, img_buffer_20hz_cl, (i+1)*frame_size_bytes, i*frame_size_bytes, frame_size_bytes, 0, nullptr, nullptr));
}
loadyuv_queue(&loadyuv, q, y_cl, u_cl, v_cl, last_img_cl);
+1 -2
View File
@@ -64,7 +64,7 @@ protected:
class DrivingModelFrame : public ModelFrame {
public:
DrivingModelFrame(cl_device_id device_id, cl_context context, uint8_t buffer_length);
DrivingModelFrame(cl_device_id device_id, cl_context context);
~DrivingModelFrame();
cl_mem* prepare(cl_mem yuv_cl, int frame_width, int frame_height, int frame_stride, int frame_uv_offset, const mat3& projection);
@@ -73,7 +73,6 @@ public:
const int MODEL_FRAME_SIZE = MODEL_WIDTH * MODEL_HEIGHT * 3 / 2;
const int buf_size = MODEL_FRAME_SIZE * 2;
const size_t frame_size_bytes = MODEL_FRAME_SIZE * sizeof(uint8_t);
const uint8_t buffer_length;
private:
LoadYUVState loadyuv;
+1 -1
View File
@@ -20,7 +20,7 @@ cdef extern from "selfdrive/modeld/models/commonmodel.h":
cppclass DrivingModelFrame:
int buf_size
DrivingModelFrame(cl_device_id, cl_context, unsigned char)
DrivingModelFrame(cl_device_id, cl_context)
cppclass MonitoringModelFrame:
int buf_size
+3 -3
View File
@@ -4,7 +4,7 @@
import numpy as np
cimport numpy as cnp
from libc.string cimport memcpy
from libc.stdint cimport uintptr_t, uint8_t
from libc.stdint cimport uintptr_t
from msgq.visionipc.visionipc cimport cl_mem
from msgq.visionipc.visionipc_pyx cimport VisionBuf, CLContext as BaseCLContext
@@ -59,8 +59,8 @@ cdef class ModelFrame:
cdef class DrivingModelFrame(ModelFrame):
cdef cppDrivingModelFrame * _frame
def __cinit__(self, CLContext context, int buffer_length=2):
self._frame = new cppDrivingModelFrame(context.device_id, context.context, buffer_length)
def __cinit__(self, CLContext context):
self._frame = new cppDrivingModelFrame(context.device_id, context.context)
self.frame = <cppModelFrame*>(self._frame)
self.buf_size = self._frame.buf_size
-5
View File
@@ -81,8 +81,3 @@ void PandaSafety::setSafetyMode(const std::string &params_string) {
pandas_[i]->set_safety_model(safety_model, safety_param);
}
}
bool PandaSafety::getOffroadMode() {
auto offroad_mode = params_.getBool("OffroadMode");
return offroad_mode;
}
+14 -22
View File
@@ -105,6 +105,9 @@ void can_send_thread(std::vector<Panda *> pandas, bool fake_send) {
while (!do_exit && check_all_connected(pandas)) {
std::unique_ptr<Message> msg(subscriber->receive());
if (!msg) {
if (errno == EINTR) {
do_exit = true;
}
continue;
}
@@ -155,6 +158,7 @@ void fill_panda_state(cereal::PandaState::Builder &ps, cereal::PandaState::Panda
ps.setIgnitionLine(health.ignition_line_pkt);
ps.setIgnitionCan(health.ignition_can_pkt);
ps.setControlsAllowed(health.controls_allowed_pkt);
ps.setControlsAllowedLat(health.controls_allowed_lat_pkt);
ps.setTxBufferOverflow(health.tx_buffer_overflow_pkt);
ps.setRxBufferOverflow(health.rx_buffer_overflow_pkt);
ps.setPandaType(hw_type);
@@ -202,7 +206,7 @@ void fill_panda_can_state(cereal::PandaState::PandaCanState::Builder &cs, const
cs.setCanCoreResetCnt(can_health.can_core_reset_cnt);
}
std::optional<bool> send_panda_states(PubMaster *pm, const std::vector<Panda *> &pandas, bool spoofing_started, PandaSafety *panda_safety) {
std::optional<bool> send_panda_states(PubMaster *pm, const std::vector<Panda *> &pandas, bool spoofing_started) {
bool ignition_local = false;
const uint32_t pandas_cnt = pandas.size();
@@ -250,7 +254,7 @@ std::optional<bool> send_panda_states(PubMaster *pm, const std::vector<Panda *>
health.ignition_line_pkt = 0;
}
ignition_local |= ((health.ignition_line_pkt != 0) || (health.ignition_can_pkt != 0)) && !panda_safety->getOffroadMode();
ignition_local |= ((health.ignition_line_pkt != 0) || (health.ignition_can_pkt != 0));
pandaStates.push_back(health);
}
@@ -337,15 +341,16 @@ void send_peripheral_state(Panda *panda, PubMaster *pm) {
pm->send("peripheralState", msg);
}
void process_panda_state(std::vector<Panda *> &pandas, PubMaster *pm, bool engaged, bool engaged_mads, bool spoofing_started,
PandaSafety *panda_safety) {
void process_panda_state(std::vector<Panda *> &pandas, PubMaster *pm, bool spoofing_started) {
static SubMaster sm({"selfdriveState", "selfdriveStateSP", "carParams"});
std::vector<std::string> connected_serials;
for (Panda *p : pandas) {
connected_serials.push_back(p->hw_serial());
}
{
auto ignition_opt = send_panda_states(pm, pandas, spoofing_started, panda_safety);
auto ignition_opt = send_panda_states(pm, pandas, spoofing_started);
if (!ignition_opt) {
LOGE("Failed to get ignition_opt");
return;
@@ -374,6 +379,9 @@ void process_panda_state(std::vector<Panda *> &pandas, PubMaster *pm, bool engag
}
}
sm.update(0);
const bool engaged = sm.allAliveAndValid({"selfdriveState"}) && sm["selfdriveState"].getSelfdriveState().getEnabled();
const bool engaged_mads = process_mads_heartbeat(&sm);
for (const auto &panda : pandas) {
panda->send_heartbeat(engaged, engaged_mads);
}
@@ -439,12 +447,9 @@ void pandad_run(std::vector<Panda *> &pandas) {
std::thread send_thread(can_send_thread, pandas, fake_send);
RateKeeper rk("pandad", 100);
SubMaster sm({"selfdriveState", "selfdriveStateSP", "carParams"});
PubMaster pm({"can", "pandaStates", "peripheralState"});
PandaSafety panda_safety(pandas);
Panda *peripheral_panda = pandas[0];
bool engaged = false;
bool engaged_mads = false;
// Main loop: receive CAN data and process states
while (!do_exit && check_all_connected(pandas)) {
@@ -457,10 +462,7 @@ void pandad_run(std::vector<Panda *> &pandas) {
// Process panda state at 10 Hz
if (rk.frame() % 10 == 0) {
sm.update(0);
engaged = sm.allAliveAndValid({"selfdriveState"}) && sm["selfdriveState"].getSelfdriveState().getEnabled();
engaged_mads = process_mads_heartbeat(&sm);
process_panda_state(pandas, &pm, engaged, engaged_mads, spoofing_started, &panda_safety);
process_panda_state(pandas, &pm, spoofing_started);
panda_safety.configureSafetyMode();
}
@@ -472,16 +474,6 @@ void pandad_run(std::vector<Panda *> &pandas) {
rk.keepTime();
}
// Close relay on exit to prevent a fault
const bool is_onroad = Params().getBool("IsOnroad");
if (is_onroad && !engaged) {
for (auto &p : pandas) {
if (p->connected()) {
p->set_safety_model(cereal::CarParams::SafetyModel::NO_OUTPUT);
}
}
}
send_thread.join();
}
-1
View File
@@ -12,7 +12,6 @@ class PandaSafety {
public:
PandaSafety(const std::vector<Panda *> &pandas) : pandas_(pandas) {}
void configureSafetyMode();
bool getOffroadMode();
private:
void updateMultiplexingMode();
+5 -18
View File
@@ -3,8 +3,8 @@
import os
import usb1
import time
import signal
import subprocess
from typing import NoReturn
from panda import Panda, PandaDFU, PandaProtocolMismatch, FW_PATH
from openpilot.common.basedir import BASEDIR
@@ -61,25 +61,13 @@ def flash_panda(panda_serial: str) -> Panda:
return panda
def main() -> None:
# signal pandad to close the relay and exit
def signal_handler(signum, frame):
cloudlog.info(f"Caught signal {signum}, exiting")
nonlocal do_exit
do_exit = True
if process is not None:
process.send_signal(signal.SIGINT)
process = None
do_exit = False
signal.signal(signal.SIGINT, signal_handler)
def main() -> NoReturn:
count = 0
first_run = True
params = Params()
no_internal_panda_count = 0
while not do_exit:
while True:
try:
count += 1
cloudlog.event("pandad.flash_and_connect", count=count)
@@ -171,9 +159,8 @@ def main() -> None:
# run pandad with all connected serials as arguments
os.environ['MANAGER_DAEMON'] = 'pandad'
process = subprocess.Popen(["./pandad", *panda_serials], cwd=os.path.join(BASEDIR, "selfdrive/pandad"))
process.wait()
os.chdir(os.path.join(BASEDIR, "selfdrive/pandad"))
subprocess.run(["./pandad", *panda_serials], check=True)
if __name__ == "__main__":
main()
+1 -2
View File
@@ -6,8 +6,7 @@ from dataclasses import dataclass
from openpilot.common.basedir import BASEDIR
from openpilot.common.params import Params
from openpilot.selfdrive.selfdrived.events import Alert
from openpilot.sunnypilot.selfdrive.selfdrived.events_base import EmptyAlert
from openpilot.selfdrive.selfdrived.events import Alert, EmptyAlert
with open(os.path.join(BASEDIR, "selfdrive/selfdrived/alerts_offroad.json")) as f:
-4
View File
@@ -44,9 +44,5 @@
"Offroad_Recalibration": {
"text": "openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield.",
"severity": 0
},
"OffroadMode_Status": {
"text": "sunnypilot is now in Always Offroad mode. sunnypilot won't start until Always Offroad mode is disabled. Go to \"Settings\" -> \"Device\" to exit Always Offroad mode.",
"severity": 1
}
}
+291 -13
View File
@@ -1,6 +1,9 @@
#!/usr/bin/env python3
import bisect
import math
import os
from enum import IntEnum
from collections.abc import Callable
from cereal import log, car
import cereal.messaging as messaging
@@ -9,11 +12,6 @@ from openpilot.common.git import get_short_branch
from openpilot.common.realtime import DT_CTRL
from openpilot.selfdrive.locationd.calibrationd import MIN_SPEED_FILTER
from openpilot.sunnypilot.selfdrive.selfdrived.events_base import EventsBase, Priority, ET, Alert, \
NoEntryAlert, SoftDisableAlert, UserSoftDisableAlert, ImmediateDisableAlert, EngagementAlert, NormalPermanentAlert, \
StartupAlert, AlertCallbackType
AlertSize = log.SelfdriveState.AlertSize
AlertStatus = log.SelfdriveState.AlertStatus
VisualAlert = car.CarControl.HUDControl.VisualAlert
@@ -21,23 +19,201 @@ AudibleAlert = car.CarControl.HUDControl.AudibleAlert
EventName = log.OnroadEvent.EventName
# Alert priorities
class Priority(IntEnum):
LOWEST = 0
LOWER = 1
LOW = 2
MID = 3
HIGH = 4
HIGHEST = 5
# Event types
class ET:
ENABLE = 'enable'
PRE_ENABLE = 'preEnable'
OVERRIDE_LATERAL = 'overrideLateral'
OVERRIDE_LONGITUDINAL = 'overrideLongitudinal'
NO_ENTRY = 'noEntry'
WARNING = 'warning'
USER_DISABLE = 'userDisable'
SOFT_DISABLE = 'softDisable'
IMMEDIATE_DISABLE = 'immediateDisable'
PERMANENT = 'permanent'
# get event name from enum
EVENT_NAME = {v: k for k, v in EventName.schema.enumerants.items()}
class Events(EventsBase):
class Events:
def __init__(self):
super().__init__()
self.events: list[int] = []
self.static_events: list[int] = []
self.event_counters = dict.fromkeys(EVENTS.keys(), 0)
def get_events_mapping(self) -> dict[int, dict[str, Alert | AlertCallbackType]]:
return EVENTS
@property
def names(self) -> list[int]:
return self.events
def get_event_name(self, event: int):
return EVENT_NAME[event]
def __len__(self) -> int:
return len(self.events)
def get_event_msg_type(self):
return log.OnroadEvent
def add(self, event_name: int, static: bool=False) -> None:
if static:
bisect.insort(self.static_events, event_name)
bisect.insort(self.events, event_name)
def clear(self) -> None:
self.event_counters = {k: (v + 1 if k in self.events else 0) for k, v in self.event_counters.items()}
self.events = self.static_events.copy()
def contains(self, event_type: str) -> bool:
return any(event_type in EVENTS.get(e, {}) for e in self.events)
def create_alerts(self, event_types: list[str], callback_args=None):
if callback_args is None:
callback_args = []
ret = []
for e in self.events:
types = EVENTS[e].keys()
for et in event_types:
if et in types:
alert = EVENTS[e][et]
if not isinstance(alert, Alert):
alert = alert(*callback_args)
if DT_CTRL * (self.event_counters[e] + 1) >= alert.creation_delay:
alert.alert_type = f"{EVENT_NAME[e]}/{et}"
alert.event_type = et
ret.append(alert)
return ret
def add_from_msg(self, events):
for e in events:
bisect.insort(self.events, e.name.raw)
def to_msg(self):
ret = []
for event_name in self.events:
event = log.OnroadEvent.new_message()
event.name = event_name
for event_type in EVENTS.get(event_name, {}):
setattr(event, event_type, True)
ret.append(event)
return ret
def has(self, event_name: int) -> bool:
return event_name in self.events
def contains_in_list(self, events_list: list[int]) -> bool:
return any(event_name in self.events for event_name in events_list)
def remove(self, event_name: int, static: bool = False) -> None:
if static and event_name in self.static_events:
self.static_events.remove(event_name)
if event_name in self.events:
self.event_counters[event_name] = self.event_counters[event_name] + 1
self.events.remove(event_name)
def replace(self, prev_event_name: int, cur_event_name: int, static: bool = False) -> None:
self.remove(prev_event_name, static)
self.add(cur_event_name, static)
class Alert:
def __init__(self,
alert_text_1: str,
alert_text_2: str,
alert_status: log.SelfdriveState.AlertStatus,
alert_size: log.SelfdriveState.AlertSize,
priority: Priority,
visual_alert: car.CarControl.HUDControl.VisualAlert,
audible_alert: car.CarControl.HUDControl.AudibleAlert,
duration: float,
creation_delay: float = 0.):
self.alert_text_1 = alert_text_1
self.alert_text_2 = alert_text_2
self.alert_status = alert_status
self.alert_size = alert_size
self.priority = priority
self.visual_alert = visual_alert
self.audible_alert = audible_alert
self.duration = int(duration / DT_CTRL)
self.creation_delay = creation_delay
self.alert_type = ""
self.event_type: str | None = None
def __str__(self) -> str:
return f"{self.alert_text_1}/{self.alert_text_2} {self.priority} {self.visual_alert} {self.audible_alert}"
def __gt__(self, alert2) -> bool:
if not isinstance(alert2, Alert):
return False
return self.priority > alert2.priority
EmptyAlert = Alert("" , "", AlertStatus.normal, AlertSize.none, Priority.LOWEST,
VisualAlert.none, AudibleAlert.none, 0)
class NoEntryAlert(Alert):
def __init__(self, alert_text_2: str,
alert_text_1: str = "openpilot Unavailable",
visual_alert: car.CarControl.HUDControl.VisualAlert=VisualAlert.none):
super().__init__(alert_text_1, alert_text_2, AlertStatus.normal,
AlertSize.mid, Priority.LOW, visual_alert,
AudibleAlert.refuse, 3.)
class SoftDisableAlert(Alert):
def __init__(self, alert_text_2: str):
super().__init__("TAKE CONTROL IMMEDIATELY", alert_text_2,
AlertStatus.userPrompt, AlertSize.full,
Priority.MID, VisualAlert.steerRequired,
AudibleAlert.warningSoft, 2.),
# less harsh version of SoftDisable, where the condition is user-triggered
class UserSoftDisableAlert(SoftDisableAlert):
def __init__(self, alert_text_2: str):
super().__init__(alert_text_2),
self.alert_text_1 = "openpilot will disengage"
class ImmediateDisableAlert(Alert):
def __init__(self, alert_text_2: str):
super().__init__("TAKE CONTROL IMMEDIATELY", alert_text_2,
AlertStatus.critical, AlertSize.full,
Priority.HIGHEST, VisualAlert.steerRequired,
AudibleAlert.warningImmediate, 4.),
class EngagementAlert(Alert):
def __init__(self, audible_alert: car.CarControl.HUDControl.AudibleAlert):
super().__init__("", "",
AlertStatus.normal, AlertSize.none,
Priority.MID, VisualAlert.none,
audible_alert, .2),
class NormalPermanentAlert(Alert):
def __init__(self, alert_text_1: str, alert_text_2: str = "", duration: float = 0.2, priority: Priority = Priority.LOWER, creation_delay: float = 0.):
super().__init__(alert_text_1, alert_text_2,
AlertStatus.normal, AlertSize.mid if len(alert_text_2) else AlertSize.small,
priority, VisualAlert.none, AudibleAlert.none, duration, creation_delay=creation_delay),
class StartupAlert(Alert):
def __init__(self, alert_text_1: str, alert_text_2: str = "Always keep hands on wheel and eyes on road", alert_status=AlertStatus.normal):
super().__init__(alert_text_1, alert_text_2,
alert_status, AlertSize.mid,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 5.),
# ********** helper functions **********
@@ -49,6 +225,8 @@ def get_display_speed(speed_ms: float, metric: bool) -> str:
# ********** alert callback functions **********
AlertCallbackType = Callable[[car.CarParams, car.CarState, messaging.SubMaster, bool, int, log.ControlsState], Alert]
def soft_disable_alert(alert_text_2: str) -> AlertCallbackType:
def func(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
@@ -794,6 +972,106 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
ET.WARNING: personality_changed_alert,
},
# sunnypilot
EventName.lkasEnable: {
ET.ENABLE: EngagementAlert(AudibleAlert.engage),
},
EventName.lkasDisable: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
},
EventName.manualSteeringRequired: {
ET.USER_DISABLE: Alert(
"Automatic Lane Centering is OFF",
"Manual Steering Required",
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.disengage, 1.),
},
EventName.manualLongitudinalRequired: {
ET.WARNING: Alert(
"Smart/Adaptive Cruise Control: OFF",
"Manual Speed Control Required",
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.none, 1.),
},
EventName.silentLkasEnable: {
ET.ENABLE: EngagementAlert(AudibleAlert.none),
},
EventName.silentLkasDisable: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.none),
},
EventName.silentBrakeHold: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.none),
ET.NO_ENTRY: NoEntryAlert("Brake Hold Active"),
},
EventName.silentWrongGear: {
ET.WARNING: Alert(
"",
"",
AlertStatus.normal, AlertSize.none,
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, 0.),
ET.NO_ENTRY: Alert(
"Gear not D",
"openpilot Unavailable",
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.none, 0.),
},
EventName.silentReverseGear: {
ET.PERMANENT: Alert(
"Reverse\nGear",
"",
AlertStatus.normal, AlertSize.full,
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .2, creation_delay=0.5),
ET.NO_ENTRY: NoEntryAlert("Reverse Gear"),
},
EventName.silentDoorOpen: {
ET.WARNING: Alert(
"",
"",
AlertStatus.normal, AlertSize.none,
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, 0.),
ET.NO_ENTRY: NoEntryAlert("Door Open"),
},
EventName.silentSeatbeltNotLatched: {
ET.WARNING: Alert(
"",
"",
AlertStatus.normal, AlertSize.none,
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, 0.),
ET.NO_ENTRY: NoEntryAlert("Seatbelt Unlatched"),
},
EventName.silentParkBrake: {
ET.WARNING: Alert(
"",
"",
AlertStatus.normal, AlertSize.none,
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, 0.),
ET.NO_ENTRY: NoEntryAlert("Parking Brake Engaged"),
},
EventName.controlsMismatchLateral: {
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Controls Mismatch: Lateral"),
ET.NO_ENTRY: NoEntryAlert("Controls Mismatch: Lateral"),
},
EventName.hyundaiRadarTracksConfirmed: {
ET.PERMANENT: NormalPermanentAlert("Radar tracks available. Restart the car to initialize")
},
EventName.experimentalModeSwitched: {
ET.WARNING: NormalPermanentAlert("Experimental Mode Switched", duration=1.5)
}
}
+16 -36
View File
@@ -5,7 +5,7 @@ import threading
import cereal.messaging as messaging
from cereal import car, log, custom
from cereal import car, log
from msgq.visionipc import VisionIpcClient, VisionStreamType
from panda import ALTERNATIVE_EXPERIENCE
@@ -25,8 +25,7 @@ from openpilot.system.version import get_build_metadata
from openpilot.sunnypilot.mads.mads import ModularAssistiveDrivingSystem
from openpilot.sunnypilot.selfdrive.car.car_specific import CarSpecificEventsSP
from openpilot.sunnypilot.selfdrive.car.cruise_helpers import CruiseHelper
from openpilot.sunnypilot.selfdrive.selfdrived.events import EventsSP
from openpilot.sunnypilot.selfdrive.car.experimental_switcher import ExperimentalSwitcher
REPLAY = "REPLAY" in os.environ
SIMULATION = "SIMULATION" in os.environ
@@ -46,8 +45,8 @@ SafetyModel = car.CarParams.SafetyModel
IGNORED_SAFETY_MODES = (SafetyModel.silent, SafetyModel.noOutput)
class SelfdriveD(CruiseHelper):
def __init__(self, CP=None, CP_SP=None):
class SelfdriveD(ExperimentalSwitcher):
def __init__(self, CP=None):
self.params = Params()
# Ensure the current branch is cached, otherwise the first cycle lags
@@ -60,18 +59,11 @@ class SelfdriveD(CruiseHelper):
else:
self.CP = CP
if CP_SP is None:
cloudlog.info("selfdrived is waiting for CarParamsSP")
self.CP_SP = messaging.log_from_bytes(self.params.get("CarParamsSP", block=True), custom.CarParamsSP)
cloudlog.info("selfdrived got CarParamsSP")
else:
self.CP_SP = CP_SP
self.car_events = CarSpecificEvents(self.CP)
self.disengage_on_accelerator = not (self.CP.alternativeExperience & ALTERNATIVE_EXPERIENCE.DISABLE_DISENGAGE_ON_GAS)
# Setup sockets
self.pm = messaging.PubMaster(['selfdriveState', 'onroadEvents'] + ['selfdriveStateSP', 'onroadEventsSP'])
self.pm = messaging.PubMaster(['selfdriveState', 'onroadEvents'])
self.gps_location_service = get_gps_location_service(self.params)
self.gps_packets = [self.gps_location_service]
@@ -143,20 +135,18 @@ class SelfdriveD(CruiseHelper):
elif self.CP.passive:
self.events.add(EventName.dashcamMode, static=True)
self.events_sp = EventsSP()
self.events_sp_prev = []
self.mads = ModularAssistiveDrivingSystem(self)
sock_services = list(self.pm.sock.keys()) + ['selfdriveStateSP']
self.pm = messaging.PubMaster(sock_services)
self.car_events_sp = CarSpecificEventsSP(self.CP, self.params)
CruiseHelper.__init__(self, self.CP)
ExperimentalSwitcher.__init__(self, self.params)
def update_events(self, CS):
"""Compute onroadEvents from carState"""
self.events.clear()
self.events_sp.clear()
if self.sm['controlsState'].lateralControlState.which() == 'debugState':
self.events.add(EventName.joystickDebug)
@@ -194,7 +184,7 @@ class SelfdriveD(CruiseHelper):
self.events.add_from_msg(car_events)
car_events_sp = self.car_events_sp.update().to_msg()
self.events_sp.add_from_msg(car_events_sp)
self.events.add_from_msg(car_events_sp)
if self.CP.notCar:
# wait for everything to init first
@@ -380,7 +370,9 @@ class SelfdriveD(CruiseHelper):
if self.sm['modelV2'].frameDropPerc > 20:
self.events.add(EventName.modeldLagging)
CruiseHelper.update(self, CS, self.events_sp, self.experimental_mode)
# toggle experimental mode once on distance button hold
if self.CP.openpilotLongitudinalControl:
ExperimentalSwitcher.update(self, CS, self.events, self.experimental_mode)
# decrement personality on distance button press
if self.CP.openpilotLongitudinalControl:
@@ -446,13 +438,9 @@ class SelfdriveD(CruiseHelper):
clear_event_types.add(ET.NO_ENTRY)
pers = LONGITUDINAL_PERSONALITY_MAP[self.personality]
callback_args = [self.CP, CS, self.sm, self.is_metric,
self.state_machine.soft_disable_timer, pers]
alerts = self.events.create_alerts(self.state_machine.current_alert_types, callback_args)
alerts_sp = self.events_sp.create_alerts(self.state_machine.current_alert_types, callback_args)
self.AM.add_many(self.sm.frame, alerts + alerts_sp)
alerts = self.events.create_alerts(self.state_machine.current_alert_types, [self.CP, CS, self.sm, self.is_metric,
self.state_machine.soft_disable_timer, pers])
self.AM.add_many(self.sm.frame, alerts)
self.AM.process_alerts(self.sm.frame, clear_event_types)
def publish_selfdriveState(self, CS):
@@ -497,21 +485,13 @@ class SelfdriveD(CruiseHelper):
self.pm.send('selfdriveStateSP', ss_sp_msg)
# onroadEventsSP - logged every second or on change
if (self.sm.frame % int(1. / DT_CTRL) == 0) or (self.events_sp.names != self.events_sp_prev):
ce_send_sp = messaging.new_message('onroadEventsSP', len(self.events_sp))
ce_send_sp.valid = True
ce_send_sp.onroadEventsSP = self.events_sp.to_msg()
self.pm.send('onroadEventsSP', ce_send_sp)
self.events_sp_prev = self.events_sp.names.copy()
def step(self):
CS = self.data_sample()
self.update_events(CS)
if not self.CP.passive and self.initialized:
self.enabled, self.active = self.state_machine.update(self.events)
if not self.CP.notCar:
self.mads.update(CS)
self.mads.update(CS, self.sm)
self.update_alerts(CS)
self.publish_selfdriveState(CS)
@@ -1,10 +1,8 @@
import random
from openpilot.selfdrive.selfdrived.events import Alert, EVENTS
from openpilot.selfdrive.selfdrived.events import Alert, EmptyAlert, EVENTS
from openpilot.selfdrive.selfdrived.alertmanager import AlertManager
from openpilot.sunnypilot.selfdrive.selfdrived.events_base import EmptyAlert
class TestAlertManager:
+1 -33
View File
@@ -8,7 +8,6 @@ from itertools import zip_longest
import matplotlib.pyplot as plt
import numpy as np
from tabulate import tabulate
from openpilot.common.git import get_commit
from openpilot.system.hardware import PC
@@ -31,11 +30,6 @@ API_TOKEN = os.getenv("GITHUB_COMMENTS_TOKEN","")
MODEL_REPLAY_BUCKET="model_replay_master"
GITHUB = GithubUtils(API_TOKEN, DATA_TOKEN)
EXEC_TIMINGS = [
# model, instant max, average max
("modelV2", 0.03, 0.025),
("driverStateV2", 0.02, 0.015),
]
def get_log_fn(test_route, ref="master"):
return f"{test_route}_model_tici_{ref}.zst"
@@ -162,33 +156,7 @@ def model_replay(lr, frs):
del frs['roadCameraState'].frames
del frs['wideRoadCameraState'].frames
dmonitoringmodeld_msgs = replay_process(dmonitoringmodeld, dmodeld_logs, frs)
msgs = modeld_msgs + dmonitoringmodeld_msgs
header = ['model', 'max instant', 'max instant allowed', 'average', 'max average allowed', 'test result']
rows = []
timings_ok = True
for (s, instant_max, avg_max) in EXEC_TIMINGS:
ts = [getattr(m, s).modelExecutionTime for m in msgs if m.which() == s]
# TODO some init can happen in first iteration
ts = ts[1:]
errors = []
if np.max(ts) > instant_max:
errors.append("❌ FAILED MAX TIMING CHECK ❌")
if np.mean(ts) > avg_max:
errors.append("❌ FAILED AVG TIMING CHECK ❌")
timings_ok = not errors and timings_ok
rows.append([s, np.max(ts), instant_max, np.mean(ts), avg_max, "\n".join(errors) or ""])
print("------------------------------------------------")
print("----------------- Model Timing -----------------")
print("------------------------------------------------")
print(tabulate(rows, header, tablefmt="simple_grid", stralign="center", numalign="center", floatfmt=".4f"))
assert timings_ok
return msgs
return modeld_msgs + dmonitoringmodeld_msgs
def get_frames():
@@ -23,7 +23,7 @@ from openpilot.common.prefix import OpenpilotPrefix
from openpilot.common.timeout import Timeout
from openpilot.common.realtime import DT_CTRL
from panda.python import ALTERNATIVE_EXPERIENCE
from openpilot.selfdrive.car.card import can_comm_callbacks, convert_to_capnp
from openpilot.selfdrive.car.card import can_comm_callbacks
from openpilot.system.manager.process_config import managed_processes
from openpilot.selfdrive.test.process_replay.vision_meta import meta_from_camera_state, available_streams
from openpilot.selfdrive.test.process_replay.migration import migrate_all
@@ -344,7 +344,6 @@ def get_car_params_callback(rc, pm, msgs, fingerprint):
if fingerprint:
CarInterface, _, _, _ = interfaces[fingerprint]
CP = CarInterface.get_non_essential_params(fingerprint)
CP_SP = CarInterface.get_non_essential_params_sp(CP, fingerprint)
else:
can = DummySocket()
sendcan = DummySocket()
@@ -365,14 +364,12 @@ def get_car_params_callback(rc, pm, msgs, fingerprint):
with car.CarParams.from_bytes(cached_params_raw) as _cached_params:
cached_params = _cached_params
_CI = get_car(*can_callbacks, lambda obd: None, Params().get_bool("ExperimentalLongitudinalEnabled"), cached_params=cached_params)
CP, CP_SP = _CI.CP, _CI.CP_SP
CP = get_car(*can_callbacks, lambda obd: None, Params().get_bool("ExperimentalLongitudinalEnabled"), cached_params=cached_params).CP
if not params.get_bool("DisengageOnAccelerator"):
CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.DISABLE_DISENGAGE_ON_GAS
params.put("CarParams", CP.to_bytes())
params.put("CarParamsSP", convert_to_capnp(CP_SP).to_bytes())
def selfdrived_rcv_callback(msg, cfg, frame):
+1
View File
@@ -74,6 +74,7 @@ if GetOption('extras'):
qt_src.remove("main.cc") # replaced by test_runner
qt_env.Program('tests/test_translations', [asset_obj, 'tests/test_runner.cc', 'tests/test_translations.cc'] + qt_src, LIBS=qt_libs)
if GetOption('extras'):
qt_env.SharedLibrary("qt/python_helpers", ["qt/qt_window.cc"], LIBS=qt_libs)
# spinner and text window
+10 -2
View File
@@ -1,3 +1,4 @@
#include <time.h>
#include <unistd.h>
#include <cstdlib>
@@ -10,7 +11,6 @@
#include <QTimer>
#include <QVBoxLayout>
#include "common/util.h"
#include "selfdrive/ui/installer/installer.h"
#include "selfdrive/ui/qt/util.h"
#include "selfdrive/ui/qt/qt_window.h"
@@ -36,6 +36,14 @@ const QString CACHE_PATH = "/data/openpilot.cache";
extern const uint8_t str_continue[] asm("_binary_selfdrive_ui_installer_continue_openpilot_sh_start");
extern const uint8_t str_continue_end[] asm("_binary_selfdrive_ui_installer_continue_openpilot_sh_end");
bool time_valid() {
time_t rawtime;
time(&rawtime);
struct tm * sys_time = gmtime(&rawtime);
return (1900 + sys_time->tm_year) >= 2020;
}
void run(const char* cmd) {
int err = std::system(cmd);
assert(err == 0);
@@ -95,7 +103,7 @@ void Installer::updateProgress(int percent) {
void Installer::doInstall() {
// wait for valid time
while (!util::system_time_valid()) {
while (!time_valid()) {
usleep(500 * 1000);
qDebug() << "Waiting for valid time";
}
-15
View File
@@ -29,11 +29,6 @@ HomeWindow::HomeWindow(QWidget* parent) : QWidget(parent) {
body = new BodyWindow(this);
slayout->addWidget(body);
driver_view = new DriverViewWindow(this);
connect(driver_view, &DriverViewWindow::done, [=] {
showDriverView(false);
});
slayout->addWidget(driver_view);
setAttribute(Qt::WA_NoSystemBackground);
QObject::connect(uiState(), &UIState::uiUpdate, this, &HomeWindow::updateState);
QObject::connect(uiState(), &UIState::offroadTransition, this, &HomeWindow::offroadTransition);
@@ -64,16 +59,6 @@ void HomeWindow::offroadTransition(bool offroad) {
}
}
void HomeWindow::showDriverView(bool show) {
if (show) {
emit closeSettings();
slayout->setCurrentWidget(driver_view);
} else {
slayout->setCurrentWidget(home);
}
sidebar->setVisible(show == false);
}
void HomeWindow::mousePressEvent(QMouseEvent* e) {
// Handle sidebar collapsing
if ((onroad->isVisible() || body->isVisible()) && (!sidebar->isVisible() || e->x() > sidebar->width())) {
-3
View File
@@ -8,7 +8,6 @@
#include <QWidget>
#include "selfdrive/ui/ui.h"
#include "selfdrive/ui/qt/offroad/driverview.h"
#ifdef SUNNYPILOT
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
@@ -41,7 +40,6 @@ signals:
public slots:
void offroadTransition(bool offroad);
void showDriverView(bool show);
void showSidebar(bool show);
protected:
@@ -52,7 +50,6 @@ protected:
OffroadHome *home;
OnroadWindow *onroad;
BodyWindow *body;
DriverViewWindow *driver_view;
QStackedLayout *slayout;
protected slots:
+1 -1
View File
@@ -97,7 +97,7 @@ public:
void setPrimeType(PrimeState::Type type);
WifiManager* wifi = nullptr;
protected:
private:
QStackedLayout* main_layout = nullptr;
QWidget* wifiScreen = nullptr;
AdvancedNetworking* an = nullptr;
@@ -29,13 +29,6 @@ DeveloperPanel::DeveloperPanel(SettingsWindow *parent) : ListWidget(parent) {
});
addItem(longManeuverToggle);
alphaLongToggle = new ParamControl("ExperimentalLongitudinalEnabled", tr("openpilot Longitudinal Control (Alpha)"), "", "../assets/offroad/icon_speed_limit.png");
QObject::connect(alphaLongToggle, &ParamControl::toggleFlipped, [=](bool state) {
updateToggles(offroad);
});
addItem(alphaLongToggle);
alphaLongToggle->setConfirmation(true, false);
// TODO-SP: Move to Vehicles panel when ported back
hyundaiRadarTracksToggle = new ParamControl(
"HyundaiRadarTracksToggle",
@@ -71,33 +64,12 @@ void DeveloperPanel::updateToggles(bool _offroad) {
capnp::FlatArrayMessageReader cmsg(aligned_buf.align(cp_bytes.data(), cp_bytes.size()));
cereal::CarParams::Reader CP = cmsg.getRoot<cereal::CarParams>();
const QString alpha_long_description = QString("<b>%1</b><br><br>%2")
.arg(tr("WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB)."))
.arg(tr("On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. "
"Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha."));
alphaLongToggle->setDescription("<b>" + alpha_long_description + "</b>");
if (!CP.getExperimentalLongitudinalAvailable() && !CP.getOpenpilotLongitudinalControl()) {
params.remove("ExperimentalLongitudinalEnabled");
alphaLongToggle->setEnabled(false);
alphaLongToggle->setDescription("<b>" + tr("openpilot longitudinal control may come in a future update.") + "</b>");
}
// if is a release branch or if the car already have long control the alphaLongToggle should not be visible
if (is_release || CP.getOpenpilotLongitudinalControl()) {
params.remove("ExperimentalLongitudinalEnabled");
alphaLongToggle->setVisible(false);
}
alphaLongToggle->refresh();
auto hyundai = CP.getCarName() == "hyundai";
auto hyundai_mando_radar = hyundai && (CP.getFlags() & 4096);
longManeuverToggle->setEnabled(hasLongitudinalControl(CP) && _offroad);
hyundaiRadarTracksToggle->setVisible(hyundai_mando_radar && hasLongitudinalControl(CP));
} else {
alphaLongToggle->setVisible(false);
longManeuverToggle->setEnabled(false);
hyundaiRadarTracksToggle->setVisible(false);
}
@@ -16,9 +16,7 @@ private:
Params params;
ParamControl* joystickToggle;
ParamControl* longManeuverToggle;
ParamControl* alphaLongToggle;
ParamControl* hyundaiRadarTracksToggle;
bool is_release;
bool offroad;
+17 -18
View File
@@ -6,24 +6,6 @@
#include "selfdrive/ui/qt/util.h"
DriverViewWindow::DriverViewWindow(QWidget* parent) : CameraWidget("camerad", VISION_STREAM_DRIVER, parent) {
QObject::connect(this, &CameraWidget::clicked, this, &DriverViewWindow::done);
QObject::connect(device(), &Device::interactiveTimeout, this, [this]() {
if (isVisible()) {
emit done();
}
});
}
void DriverViewWindow::showEvent(QShowEvent* event) {
params.putBool("IsDriverViewEnabled", true);
device()->resetInteractiveTimeout(60);
CameraWidget::showEvent(event);
}
void DriverViewWindow::hideEvent(QHideEvent* event) {
params.putBool("IsDriverViewEnabled", false);
stopVipcThread();
CameraWidget::hideEvent(event);
}
void DriverViewWindow::paintGL() {
@@ -80,3 +62,20 @@ mat4 DriverViewWindow::calcFrameMatrix() {
0.0, 0.0, 0.0, 1.0,
}};
}
DriverViewDialog::DriverViewDialog(QWidget *parent) : DialogBase(parent) {
Params().putBool("IsDriverViewEnabled", true);
device()->resetInteractiveTimeout(60);
QVBoxLayout *main_layout = new QVBoxLayout(this);
main_layout->setContentsMargins(0, 0, 0, 0);
auto camera = new DriverViewWindow(this);
main_layout->addWidget(camera);
QObject::connect(camera, &DriverViewWindow::clicked, this, &DialogBase::accept);
QObject::connect(device(), &Device::interactiveTimeout, this, &DialogBase::accept);
}
void DriverViewDialog::done(int r) {
Params().putBool("IsDriverViewEnabled", false);
QDialog::done(r);
}
+9 -11
View File
@@ -2,22 +2,20 @@
#include "selfdrive/ui/qt/widgets/cameraview.h"
#include "selfdrive/ui/qt/onroad/driver_monitoring.h"
#include "selfdrive/ui/qt/widgets/input.h"
class DriverViewWindow : public CameraWidget {
Q_OBJECT
public:
explicit DriverViewWindow(QWidget *parent);
signals:
void done();
protected:
mat4 calcFrameMatrix() override;
void showEvent(QShowEvent *event) override;
void hideEvent(QHideEvent *event) override;
void paintGL() override;
Params params;
mat4 calcFrameMatrix() override;
DriverMonitorRenderer driver_monitor;
};
class DriverViewDialog : public DialogBase {
Q_OBJECT
public:
DriverViewDialog(QWidget *parent);
void done(int r) override;
};
+24 -2
View File
@@ -8,6 +8,7 @@
#include "common/watchdog.h"
#include "common/util.h"
#include "selfdrive/ui/qt/offroad/driverview.h"
#include "selfdrive/ui/qt/network/networking.h"
#include "selfdrive/ui/qt/offroad/settings.h"
#include "selfdrive/ui/qt/qt_window.h"
@@ -24,6 +25,15 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) {
tr("Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off."),
"../assets/img_chffr_wheel.png",
},
{
"ExperimentalLongitudinalEnabled",
tr("openpilot Longitudinal Control (Alpha)"),
QString("<b>%1</b><br><br>%2")
.arg(tr("WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB)."))
.arg(tr("On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. "
"Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.")),
"../assets/offroad/icon_speed_limit.png",
},
{
"ExperimentalMode",
tr("Experimental Mode"),
@@ -100,6 +110,11 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) {
toggles["ExperimentalMode"]->setActiveIcon("../assets/img_experimental.svg");
#endif
toggles["ExperimentalMode"]->setConfirmation(true, true);
toggles["ExperimentalLongitudinalEnabled"]->setConfirmation(true, false);
connect(toggles["ExperimentalLongitudinalEnabled"], &ToggleControl::toggleFlipped, [=]() {
updateToggles();
});
}
void TogglesPanel::updateState(const UIState &s) {
@@ -124,6 +139,7 @@ void TogglesPanel::showEvent(QShowEvent *event) {
void TogglesPanel::updateToggles() {
auto experimental_mode_toggle = toggles["ExperimentalMode"];
auto op_long_toggle = toggles["ExperimentalLongitudinalEnabled"];
const QString e2e_description = QString("%1<br>"
"<h4>%2</h4><br>"
"%3<br>"
@@ -147,6 +163,7 @@ void TogglesPanel::updateToggles() {
if (!CP.getExperimentalLongitudinalAvailable() || is_release) {
params.remove("ExperimentalLongitudinalEnabled");
}
op_long_toggle->setVisible(CP.getExperimentalLongitudinalAvailable() && !is_release);
if (hasLongitudinalControl(CP)) {
// normal description and toggle
experimental_mode_toggle->setEnabled(true);
@@ -175,6 +192,7 @@ void TogglesPanel::updateToggles() {
experimental_mode_toggle->refresh();
} else {
experimental_mode_toggle->setDescription(e2e_description);
op_long_toggle->setVisible(false);
}
}
@@ -200,7 +218,12 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) {
auto dcamBtn = new ButtonControl(tr("Driver Camera"), tr("PREVIEW"),
tr("Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off)"));
connect(dcamBtn, &ButtonControl::clicked, [=]() { emit showDriverView(); });
connect(dcamBtn, &ButtonControl::clicked, [this, dcamBtn]() {
dcamBtn->setEnabled(false);
DriverViewDialog driver_view(this);
driver_view.exec();
dcamBtn->setEnabled(true);
});
addItem(dcamBtn);
#endif
@@ -374,7 +397,6 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) {
// setup panels
DevicePanel *device = new DevicePanel(this);
QObject::connect(device, &DevicePanel::reviewTrainingGuide, this, &SettingsWindow::reviewTrainingGuide);
QObject::connect(device, &DevicePanel::showDriverView, this, &SettingsWindow::showDriverView);
TogglesPanel *toggles = new TogglesPanel(this);
QObject::connect(this, &SettingsWindow::expandToggleDescription, toggles, &TogglesPanel::expandToggleDescription);
-2
View File
@@ -40,7 +40,6 @@ protected:
signals:
void closeSettings();
void reviewTrainingGuide();
void showDriverView();
void expandToggleDescription(const QString &param);
protected:
@@ -57,7 +56,6 @@ public:
signals:
void reviewTrainingGuide();
void showDriverView();
protected slots:
void poweroff();
-2
View File
@@ -79,9 +79,7 @@ CameraWidget::~CameraWidget() {
glDeleteVertexArrays(1, &frame_vao);
glDeleteBuffers(1, &frame_vbo);
glDeleteBuffers(1, &frame_ibo);
#ifndef QCOM2
glDeleteTextures(2, textures);
#endif
}
doneCurrent();
}
+12 -27
View File
@@ -10,12 +10,10 @@
const QString BACKSPACE_KEY = "";
const QString ENTER_KEY = "";
const QString SHIFT_KEY = "";
const QString CAPS_LOCK_KEY = "";
const QMap<QString, int> KEY_STRETCH = {{" ", 3}, {ENTER_KEY, 2}};
const QStringList CONTROL_BUTTONS = {SHIFT_KEY, CAPS_LOCK_KEY, "ABC", "#+=", "123", BACKSPACE_KEY, ENTER_KEY};
const QStringList CONTROL_BUTTONS = {"", "", "ABC", "#+=", "123", BACKSPACE_KEY, ENTER_KEY};
const float key_spacing_vertical = 20;
const float key_spacing_horizontal = 15;
@@ -108,7 +106,7 @@ Keyboard::Keyboard(QWidget *parent) : QFrame(parent) {
std::vector<QVector<QString>> lowercase = {
{"q", "w", "e", "r", "t", "y", "u", "i", "o", "p"},
{"a", "s", "d", "f", "g", "h", "j", "k", "l"},
{SHIFT_KEY, "z", "x", "c", "v", "b", "n", "m", BACKSPACE_KEY},
{"", "z", "x", "c", "v", "b", "n", "m", BACKSPACE_KEY},
{"123", "/", "-", " ", ".", ENTER_KEY},
};
main_layout->addWidget(new KeyboardLayout(this, lowercase));
@@ -117,7 +115,7 @@ Keyboard::Keyboard(QWidget *parent) : QFrame(parent) {
std::vector<QVector<QString>> uppercase = {
{"Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P"},
{"A", "S", "D", "F", "G", "H", "J", "K", "L"},
{SHIFT_KEY, "Z", "X", "C", "V", "B", "N", "M", BACKSPACE_KEY},
{"", "Z", "X", "C", "V", "B", "N", "M", BACKSPACE_KEY},
{"123", "/", "-", " ", ".", ENTER_KEY},
};
main_layout->addWidget(new KeyboardLayout(this, uppercase));
@@ -143,39 +141,26 @@ Keyboard::Keyboard(QWidget *parent) : QFrame(parent) {
main_layout->setCurrentIndex(0);
}
void Keyboard::handleCapsPress() {
shift_state = (shift_state + 1) % 3;
bool is_uppercase = shift_state > 0;
main_layout->setCurrentIndex(is_uppercase);
for (KeyButton* btn : main_layout->currentWidget()->findChildren<KeyButton*>()) {
if (btn->text() == SHIFT_KEY || btn->text() == CAPS_LOCK_KEY) {
btn->setText(shift_state == 2 ? CAPS_LOCK_KEY : SHIFT_KEY);
btn->setStyleSheet(is_uppercase ? "background-color: #465BEA;" : "");
}
}
}
void Keyboard::handleButton(QAbstractButton* btn) {
const QString &key = btn->text();
if (CONTROL_BUTTONS.contains(key)) {
if (key == "ABC" || key == "123" || key == "#+=") {
int index = (key == "ABC") ? 0 : (key == "123" ? 2 : 3);
main_layout->setCurrentIndex(index);
shift_state = 0;
} else if (key == SHIFT_KEY || key == CAPS_LOCK_KEY) {
handleCapsPress();
if (key == "" || key == "ABC") {
main_layout->setCurrentIndex(0);
} else if (key == "") {
main_layout->setCurrentIndex(1);
} else if (key == "123") {
main_layout->setCurrentIndex(2);
} else if (key == "#+=") {
main_layout->setCurrentIndex(3);
} else if (key == ENTER_KEY) {
main_layout->setCurrentIndex(0);
shift_state = 0;
emit emitEnter();
} else if (key == BACKSPACE_KEY) {
emit emitBackspace();
}
} else {
if (shift_state == 1 && "A" <= key && key <= "Z") {
if ("A" <= key && key <= "Z") {
main_layout->setCurrentIndex(0);
shift_state = 0;
}
emit emitKey(key);
}
-2
View File
@@ -29,11 +29,9 @@ public:
private:
QStackedLayout* main_layout;
int shift_state = 0;
private slots:
void handleButton(QAbstractButton* m_button);
void handleCapsPress();
signals:
void emitKey(const QString &s);
-3
View File
@@ -23,9 +23,6 @@ MainWindow::MainWindow(QWidget *parent, HomeWindow *hw, SettingsWindow *sw) :
onboardingWindow->showTrainingGuide();
main_layout->setCurrentWidget(onboardingWindow);
});
QObject::connect(settingsWindow, &SettingsWindow::showDriverView, [=] {
homeWindow->showDriverView(true);
});
onboardingWindow = new OnboardingWindow(this);
main_layout->addWidget(onboardingWindow);
-1
View File
@@ -4,7 +4,6 @@ widgets_src = [
"sunnypilot/qt/widgets/drive_stats.cc",
"sunnypilot/qt/widgets/prime.cc",
"sunnypilot/qt/widgets/scrollview.cc",
"sunnypilot/qt/network/networking.cc",
]
qt_util = [
@@ -1,45 +0,0 @@
#include "selfdrive/ui/sunnypilot/qt/network/networking.h"
#include <QVBoxLayout>
#include <QPushButton>
#include <QStackedLayout>
NetworkingSP::NetworkingSP(QWidget *parent) : Networking(parent) {
auto vlayout = wifiScreen->findChild<QVBoxLayout*>();
auto hlayout = new QHBoxLayout();
// Create and setup scan button
auto scanButton = new QPushButton(tr("Scan"));
scanButton->setObjectName("scan_btn");
scanButton->setFixedSize(400, 100);
connect(wifi, &WifiManager::refreshSignal, this, [=]() { scanButton->setText(tr("Scan")); scanButton->setEnabled(true); });
connect(scanButton, &QPushButton::clicked, [=]() { scanButton->setText(tr("Scanning...")); scanButton->setEnabled(false); wifi->requestScan(); });
hlayout->addWidget(scanButton);
hlayout->addStretch(1);
// Look for an existing Advanced button
QPushButton* existingAdvanced = wifiScreen->findChild<QPushButton*>("advanced_btn");
if (existingAdvanced) {
hlayout->addWidget(existingAdvanced);
}
// Insert our new layout at the top of vlayout
vlayout->setMargin(40);
vlayout->insertLayout(0, hlayout);
// Add our scan button to the existing style selectors
auto newStyleSheet = styleSheet().replace(
", #advanced_btn ",
", #advanced_btn, #scan_btn "
).replace(
", #advanced_btn:pressed",
", #advanced_btn:pressed, #scan_btn:pressed"
).append(R"(
#scan_btn:disabled {
background-color: #121212;
color: #33FFFFFF;
}
)");
setStyleSheet(newStyleSheet);
}
@@ -1,17 +0,0 @@
/**
* Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
*
* This file is part of sunnypilot and is licensed under the MIT License.
* See the LICENSE.md file in the root directory for more details.
*/
#pragma once
#include "selfdrive/ui/qt/network/networking.h"
class NetworkingSP : public Networking {
Q_OBJECT
public:
explicit NetworkingSP(QWidget *parent = nullptr);
};
@@ -8,6 +8,7 @@
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.h"
#include "common/watchdog.h"
#include "selfdrive/ui/qt/offroad/driverview.h"
#include "selfdrive/ui/qt/qt_window.h"
DevicePanelSP::DevicePanelSP(SettingsWindowSP *parent) : DevicePanel(parent) {
@@ -40,7 +41,12 @@ DevicePanelSP::DevicePanelSP(SettingsWindowSP *parent) : DevicePanel(parent) {
}
}
connect(buttons["dcamBtn"], &PushButtonSP::clicked, [=]() { emit showDriverView(); });
connect(buttons["dcamBtn"], &PushButtonSP::clicked, [this]() {
buttons["dcamBtn"]->setEnabled(false);
DriverViewDialog driver_view(this);
driver_view.exec();
buttons["dcamBtn"]->setEnabled(true);
});
connect(buttons["retrainingBtn"], &PushButtonSP::clicked, [=]() {
if (ConfirmationDialog::confirm(tr("Are you sure you want to review the training guide?"), tr("Review"), this)) {
@@ -68,17 +74,23 @@ DevicePanelSP::DevicePanelSP(SettingsWindowSP *parent) : DevicePanel(parent) {
addItem(device_grid_layout);
QObject::connect(uiState(), &UIState::offroadTransition, [=](bool offroad) {
for (auto btn : findChildren<PushButtonSP*>()) {
btn->setEnabled(offroad);
}
});
// offroad mode and power buttons
QHBoxLayout *power_layout = new QHBoxLayout();
power_layout->setSpacing(5);
PushButtonSP *rebootBtn = new PushButtonSP(tr("Reboot"), 720, this);
QPushButton *rebootBtn = new PushButtonSP(tr("Reboot"), 720, this);
rebootBtn->setStyleSheet(rebootButtonStyle);
power_layout->addWidget(rebootBtn);
QObject::connect(rebootBtn, &PushButtonSP::clicked, this, &DevicePanelSP::reboot);
PushButtonSP *poweroffBtn = new PushButtonSP(tr("Power Off"), 720, this);
QPushButton *poweroffBtn = new PushButtonSP(tr("Power Off"), 720, this);
poweroffBtn->setStyleSheet(powerOffButtonStyle);
power_layout->addWidget(poweroffBtn);
QObject::connect(poweroffBtn, &PushButtonSP::clicked, this, &DevicePanelSP::poweroff);
@@ -87,60 +99,5 @@ DevicePanelSP::DevicePanelSP(SettingsWindowSP *parent) : DevicePanel(parent) {
connect(uiState(), &UIState::offroadTransition, poweroffBtn, &PushButtonSP::setVisible);
}
offroadBtn = new PushButtonSP(tr("Offroad Mode"));
offroadBtn->setFixedWidth(power_layout->sizeHint().width());
QObject::connect(offroadBtn, &PushButtonSP::clicked, this, &DevicePanelSP::setOffroadMode);
QVBoxLayout *power_group_layout = new QVBoxLayout();
power_group_layout->setSpacing(30);
power_group_layout->addWidget(offroadBtn, 0, Qt::AlignHCenter);
power_group_layout->addLayout(power_layout);
addItem(power_group_layout);
QObject::connect(uiState(), &UIState::offroadTransition, [=](bool offroad) {
for (auto btn : findChildren<PushButtonSP*>()) {
if (btn != rebootBtn && btn != poweroffBtn && btn != offroadBtn) {
btn->setEnabled(offroad);
}
}
});
}
void DevicePanelSP::setOffroadMode() {
if (!uiState()->engaged()) {
if (params.getBool("OffroadMode")) {
if (ConfirmationDialog::confirm(tr("Are you sure you want to exit Always Offroad mode?"), tr("Confirm"), this)) {
// Check engaged again in case it changed while the dialog was open
if (!uiState()->engaged()) {
params.remove("OffroadMode");
}
}
} else {
if (ConfirmationDialog::confirm(tr("Are you sure you want to enter Always Offroad mode?"), tr("Confirm"), this)) {
// Check engaged again in case it changed while the dialog was open
if (!uiState()->engaged()) {
params.putBool("OffroadMode", true);
}
}
}
} else {
ConfirmationDialog::alert(tr("Disengage to Enter Always Offroad Mode"), this);
}
updateState();
}
void DevicePanelSP::showEvent(QShowEvent *event) {
updateState();
}
void DevicePanelSP::updateState() {
if (!isVisible()) {
return;
}
bool offroad_mode_param = params.getBool("OffroadMode");
offroadBtn->setText(offroad_mode_param ? tr("Exit Always Offroad") : tr("Always Offroad"));
offroadBtn->setStyleSheet(offroad_mode_param ? alwaysOffroadStyle : autoOffroadStyle);
addItem(power_layout);
}
@@ -15,43 +15,9 @@ class DevicePanelSP : public DevicePanel {
public:
explicit DevicePanelSP(SettingsWindowSP *parent = 0);
void showEvent(QShowEvent *event) override;
void setOffroadMode();
void updateState();
private:
std::map<QString, PushButtonSP*> buttons;
PushButtonSP *offroadBtn;
const QString alwaysOffroadStyle = R"(
PushButtonSP {
border-radius: 20px;
font-size: 50px;
font-weight: 450;
height: 150px;
padding: 0 25px 0 25px;
color: #FFFFFF;
background-color: #393939;
}
PushButtonSP:pressed {
background-color: #4A4A4A;
}
)";
const QString autoOffroadStyle = R"(
PushButtonSP {
border-radius: 20px;
font-size: 50px;
font-weight: 450;
height: 150px;
padding: 0 25px 0 25px;
color: #FFFFFF;
background-color: #E22C2C;
}
PushButtonSP:pressed {
background-color: #FF2424;
}
)";
const QString rebootButtonStyle = R"(
PushButtonSP {
@@ -7,9 +7,9 @@
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h"
#include "selfdrive/ui/qt/network/networking.h"
#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h"
#include "selfdrive/ui/qt/offroad/developer_panel.h"
#include "selfdrive/ui/sunnypilot/qt/network/networking.h"
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.h"
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/software_panel.h"
@@ -62,13 +62,12 @@ SettingsWindowSP::SettingsWindowSP(QWidget *parent) : SettingsWindow(parent) {
// setup panels
DevicePanelSP *device = new DevicePanelSP(this);
QObject::connect(device, &DevicePanelSP::reviewTrainingGuide, this, &SettingsWindowSP::reviewTrainingGuide);
QObject::connect(device, &DevicePanelSP::showDriverView, this, &SettingsWindowSP::showDriverView);
TogglesPanelSP *toggles = new TogglesPanelSP(this);
QObject::connect(this, &SettingsWindowSP::expandToggleDescription, toggles, &TogglesPanel::expandToggleDescription);
auto networking = new NetworkingSP(this);
QObject::connect(uiState()->prime_state, &PrimeState::changed, networking, &NetworkingSP::setPrimeType);
auto networking = new Networking(this);
QObject::connect(uiState()->prime_state, &PrimeState::changed, networking, &Networking::setPrimeType);
QList<PanelInfo> panels = {
PanelInfo(" " + tr("Device"), device, "../../sunnypilot/selfdrive/assets/offroad/icon_home.svg"),
-10
View File
@@ -40,14 +40,6 @@ def setup_homescreen(click, pm: PubMaster, scroll=None):
def setup_settings_device(click, pm: PubMaster, scroll=None):
click(100, 100)
def setup_settings_network(click, pm: PubMaster, scroll=None):
setup_settings_device(click, pm)
click(278, 405)
def setup_settings_network_advanced(click, pm: PubMaster, scroll=None):
setup_settings_network(click, pm)
click(1913, 90)
def setup_settings_toggles(click, pm: PubMaster, scroll=None):
setup_settings_device(click, pm)
click(278, 632)
@@ -220,8 +212,6 @@ CASES = {
"prime": setup_homescreen,
"pair_device": setup_pair_device,
"settings_device": setup_settings_device,
"settings_network": setup_settings_network,
"settings_network_advanced": setup_settings_network_advanced,
"settings_toggles": setup_settings_toggles,
"settings_software": setup_settings_software,
"settings_developer": setup_settings_developer,
+110 -157
View File
@@ -124,27 +124,7 @@
<translation>وضع المناورة الطولية</translation>
</message>
<message>
<source>openpilot Longitudinal Control (Alpha)</source>
<translation>التحكم الطولي openpilot (ألفا)</translation>
</message>
<message>
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
<translation>تحذير: التحكم الطولي في openpilot في المرحلة ألفا لهذه السيارة، وسيقوم بتعطيل مكابح الطوارئ الآلية (AEB).</translation>
</message>
<message>
<source>On this car, openpilot defaults to the car&apos;s built-in ACC instead of openpilot&apos;s longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
<translation>في هذه السيارة يعمل openpilot افتراضياً بالشكل المدمج في التحكم التكيفي في السرعة بدلاً من التحكم الطولي. قم بتمكين هذا الخيار من أجل الانتقال إلى التحكم الطولي. يوصى بتمكين الوضع التجريبي عند استخدام وضع التحكم الطولي ألفا من openpilot.</translation>
</message>
<message>
<source>openpilot longitudinal control may come in a future update.</source>
<translation>قد يتم الحصول على التحكم الطولي في openpilot في عمليات التحديث المستقبلية.</translation>
</message>
<message>
<source>Hyundai: Enable Radar Tracks</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
<source>Enables or disables the github runner service.</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -152,7 +132,11 @@
<translation type="unfinished"></translation>
</message>
<message>
<source>Enables or disables the github runner service.</source>
<source>Hyundai: Enable Radar Tracks</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
<translation type="unfinished"></translation>
</message>
</context>
@@ -309,14 +293,18 @@
<source>Training Guide</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Regulatory</source>
<translation type="unfinished">التنظيمية</translation>
</message>
<message>
<source>Language</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reboot</source>
<translation type="unfinished">إعادة التشغيل</translation>
</message>
<message>
<source>Regulatory</source>
<translation type="unfinished">التنظيمية</translation>
</message>
<message>
<source>Are you sure you want to review the training guide?</source>
<translation type="unfinished">هل أنت متأكد أنك تريد مراجعة دليل التدريب؟</translation>
@@ -329,68 +317,36 @@
<source>Select a language</source>
<translation type="unfinished">اختر لغة</translation>
</message>
<message>
<source>Reboot</source>
<translation type="unfinished">إعادة التشغيل</translation>
</message>
<message>
<source>Power Off</source>
<translation type="unfinished">إيقاف التشغيل</translation>
</message>
<message>
<source>Offroad Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Are you sure you want to exit Always Offroad mode?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Confirm</source>
<translation type="unfinished">تأكيد</translation>
</message>
<message>
<source>Are you sure you want to enter Always Offroad mode?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Disengage to Enter Always Offroad Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Exit Always Offroad</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Always Offroad</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>DriveStats</name>
<message>
<source>Drives</source>
<translation type="unfinished"></translation>
<translation>القيادة</translation>
</message>
<message>
<source>Hours</source>
<translation type="unfinished"></translation>
<translation>ساعات</translation>
</message>
<message>
<source>ALL TIME</source>
<translation type="unfinished"></translation>
<translation>كامل الوقت</translation>
</message>
<message>
<source>PAST WEEK</source>
<translation type="unfinished"></translation>
<translation>الأسبوع الماضي</translation>
</message>
<message>
<source>KM</source>
<translation type="unfinished"></translation>
<translation>كم</translation>
</message>
<message>
<source>Miles</source>
<translation type="unfinished"></translation>
<translation>ميل</translation>
</message>
</context>
<context>
@@ -457,10 +413,6 @@
<source>Toggle with Main Cruise</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unified Engagement Mode (UEM)</source>
<translation type="unfinished"></translation>
@@ -492,6 +444,10 @@ Remain Active: ALC will remain active even after the brake pedal is pressed.
Pause Steering: ALC will be paused after the brake pedal is manually pressed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MultiOptionDialog</name>
@@ -523,17 +479,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<translation>كلمة مرور خاطئة</translation>
</message>
</context>
<context>
<name>NetworkingSP</name>
<message>
<source>Scan</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Scanning...</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>OffroadAlert</name>
<message>
@@ -582,10 +527,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<source>openpilot detected a change in the device&apos;s mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield.</source>
<translation>لقد اكتشف openpilot تغييراً في موقع تركيب الجهاز. تأكد من تثبيت الجهاز بشكل كامل في موقعه وتثبيته بإحكام على الزجاج الأمامي.</translation>
</message>
<message>
<source>sunnypilot is now in Always Offroad mode. sunnypilot won&apos;t start until Always Offroad mode is disabled. Go to &quot;Settings&quot; -&gt; &quot;Device&quot; to exit Always Offroad mode.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>OffroadHome</name>
@@ -645,7 +586,7 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
</message>
<message>
<source>Please connect to Wi-Fi to complete initial pairing</source>
<translation>يرجى الاتصال بشبكة الواي فاي لإكمال الاقتران الأولي</translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>
@@ -663,11 +604,11 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<name>ParamControlSP</name>
<message>
<source>Enable</source>
<translation type="unfinished">تمكين</translation>
<translation>تمكين</translation>
</message>
<message>
<source>Cancel</source>
<translation type="unfinished">إلغاء</translation>
<translation>إلغاء</translation>
</message>
</context>
<context>
@@ -836,40 +777,40 @@ This may take up to a minute.</source>
<name>SettingsWindowSP</name>
<message>
<source>×</source>
<translation type="unfinished">×</translation>
<translation>×</translation>
</message>
<message>
<source>Device</source>
<translation type="unfinished">الجهاز</translation>
<translation>الجهاز</translation>
</message>
<message>
<source>Network</source>
<translation type="unfinished">الشبكة</translation>
<translation>الشبكة</translation>
</message>
<message>
<source>Toggles</source>
<translation>المثبتتات</translation>
</message>
<message>
<source>Software</source>
<translation>البرنامج</translation>
</message>
<message>
<source>Developer</source>
<translation>المطور</translation>
</message>
<message>
<source>sunnypilot</source>
<translation>sunnypilot</translation>
</message>
<message>
<source>sunnylink</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Toggles</source>
<translation type="unfinished">المثبتتات</translation>
</message>
<message>
<source>Software</source>
<translation type="unfinished">البرنامج</translation>
</message>
<message>
<source>sunnypilot</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Trips</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Developer</source>
<translation type="unfinished">المطور</translation>
</message>
</context>
<context>
<name>Setup</name>
@@ -1160,16 +1101,32 @@ This may take up to a minute.</source>
</context>
<context>
<name>SoftwarePanelSP</name>
<message>
<source>Current Model</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>SELECT</source>
<translation type="unfinished">اختيار</translation>
</message>
<message>
<source>No custom model selected!</source>
<source>Reset Calibration</source>
<translation type="unfinished">إعادة ضبط المعايرة</translation>
</message>
<message>
<source>Warning: You are on a metered connection!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Continue</source>
<translation type="unfinished">متابعة</translation>
</message>
<message>
<source>on Metered</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] pending...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Current Model</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1188,6 +1145,22 @@ This may take up to a minute.</source>
<source>Downloading %1 model [%2]... (%3%)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] download failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Select a Model</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Fetching models...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Model download has started in the background.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] %3</source>
<translation type="unfinished"></translation>
@@ -1204,24 +1177,12 @@ This may take up to a minute.</source>
<source>from cache</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] download failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] pending...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Fetching models...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Use Default</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Select a Model</source>
<source>No custom model selected!</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1229,7 +1190,11 @@ This may take up to a minute.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Model download has started in the background.</source>
<source>Cancel</source>
<translation type="unfinished">إلغاء</translation>
</message>
<message>
<source>Driving Model Selector</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1240,30 +1205,6 @@ This may take up to a minute.</source>
<source>Would you like to do that now?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reset Calibration</source>
<translation type="unfinished">إعادة ضبط المعايرة</translation>
</message>
<message>
<source>Driving Model Selector</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Warning: You are on a metered connection!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Continue</source>
<translation type="unfinished">متابعة</translation>
</message>
<message>
<source>on Metered</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Cancel</source>
<translation type="unfinished">إلغاء</translation>
</message>
</context>
<context>
<name>SshControl</name>
@@ -1322,11 +1263,11 @@ This may take up to a minute.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>🎉Welcome back! We&apos;re excited to see you&apos;ve enabled sunnylink again! 🚀</source>
<translation type="unfinished"></translation>
<source>N/A</source>
<translation type="unfinished">غير متاح</translation>
</message>
<message>
<source>👋Not going to lie, it&apos;s sad to see you disabled sunnylink 😢, but we&apos;ll be here when you&apos;re ready to come back 🎉.</source>
<source>🎉Welcome back! We&apos;re excited to see you&apos;ve enabled sunnylink again! 🚀</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1334,12 +1275,16 @@ This may take up to a minute.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>N/A</source>
<translation type="unfinished">غير متاح</translation>
<source>👋Not going to lie, it&apos;s sad to see you disabled sunnylink 😢, but we&apos;ll be here when you&apos;re ready to come back 🎉.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SunnypilotPanel</name>
<message>
<source>Customize MADS</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Modular Assistive Driving System (MADS)</source>
<translation type="unfinished"></translation>
@@ -1348,10 +1293,6 @@ This may take up to a minute.</source>
<source>Enable the beloved MADS feature. Disable toggle to revert back to stock openpilot engagement/disengagement.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Customize MADS</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>TermsPage</name>
@@ -1414,6 +1355,18 @@ This may take up to a minute.</source>
<source>When enabled, pressing the accelerator pedal will disengage openpilot.</source>
<translation>عند تمكين هذه الميزة، فإن الضغط على دواسة الوقود سيؤدي إلى فك ارتباط openpilot.</translation>
</message>
<message>
<source>openpilot Longitudinal Control (Alpha)</source>
<translation>التحكم الطولي openpilot (ألفا)</translation>
</message>
<message>
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
<translation>تحذير: التحكم الطولي في openpilot في المرحلة ألفا لهذه السيارة، وسيقوم بتعطيل مكابح الطوارئ الآلية (AEB).</translation>
</message>
<message>
<source>On this car, openpilot defaults to the car&apos;s built-in ACC instead of openpilot&apos;s longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
<translation>في هذه السيارة يعمل openpilot افتراضياً بالشكل المدمج في التحكم التكيفي في السرعة بدلاً من التحكم الطولي. قم بتمكين هذا الخيار من أجل الانتقال إلى التحكم الطولي. يوصى بتمكين الوضع التجريبي عند استخدام وضع التحكم الطولي ألفا من openpilot.</translation>
</message>
<message>
<source>Experimental Mode</source>
<translation>الوضع التجريبي</translation>
+107 -154
View File
@@ -124,19 +124,11 @@
<translation type="unfinished"></translation>
</message>
<message>
<source>openpilot Longitudinal Control (Alpha)</source>
<source>Enables or disables the github runner service.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>On this car, openpilot defaults to the car&apos;s built-in ACC instead of openpilot&apos;s longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>openpilot longitudinal control may come in a future update.</source>
<source>Enable GitHub runner service</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -147,14 +139,6 @@
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable GitHub runner service</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enables or disables the github runner service.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>DevicePanel</name>
@@ -309,14 +293,18 @@
<source>Training Guide</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Regulatory</source>
<translation type="unfinished">Rechtliche Hinweise</translation>
</message>
<message>
<source>Language</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reboot</source>
<translation type="unfinished">Neustart</translation>
</message>
<message>
<source>Regulatory</source>
<translation type="unfinished">Rechtliche Hinweise</translation>
</message>
<message>
<source>Are you sure you want to review the training guide?</source>
<translation type="unfinished">Bist du sicher, dass du die Trainingsanleitung wiederholen möchtest?</translation>
@@ -329,68 +317,36 @@
<source>Select a language</source>
<translation type="unfinished">Sprache wählen</translation>
</message>
<message>
<source>Reboot</source>
<translation type="unfinished">Neustart</translation>
</message>
<message>
<source>Power Off</source>
<translation type="unfinished">Ausschalten</translation>
</message>
<message>
<source>Offroad Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Are you sure you want to exit Always Offroad mode?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Confirm</source>
<translation type="unfinished">Bestätigen</translation>
</message>
<message>
<source>Are you sure you want to enter Always Offroad mode?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Disengage to Enter Always Offroad Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Exit Always Offroad</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Always Offroad</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>DriveStats</name>
<message>
<source>Drives</source>
<translation type="unfinished"></translation>
<translation>Fahrten</translation>
</message>
<message>
<source>Hours</source>
<translation type="unfinished"></translation>
<translation>Stunden</translation>
</message>
<message>
<source>ALL TIME</source>
<translation type="unfinished"></translation>
<translation>Gesamtzeit</translation>
</message>
<message>
<source>PAST WEEK</source>
<translation type="unfinished"></translation>
<translation>Letzte Woche</translation>
</message>
<message>
<source>KM</source>
<translation type="unfinished"></translation>
<translation>KM</translation>
</message>
<message>
<source>Miles</source>
<translation type="unfinished"></translation>
<translation>Meilen</translation>
</message>
</context>
<context>
@@ -453,10 +409,6 @@
<source>Toggle with Main Cruise</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unified Engagement Mode (UEM)</source>
<translation type="unfinished"></translation>
@@ -488,6 +440,10 @@ Remain Active: ALC will remain active even after the brake pedal is pressed.
Pause Steering: ALC will be paused after the brake pedal is manually pressed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MultiOptionDialog</name>
@@ -519,17 +475,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<translation>Falsches Passwort</translation>
</message>
</context>
<context>
<name>NetworkingSP</name>
<message>
<source>Scan</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Scanning...</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>OffroadAlert</name>
<message>
@@ -577,10 +522,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<source>Device temperature too high. System cooling down before starting. Current internal component temperature: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>sunnypilot is now in Always Offroad mode. sunnypilot won&apos;t start until Always Offroad mode is disabled. Go to &quot;Settings&quot; -&gt; &quot;Device&quot; to exit Always Offroad mode.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>OffroadHome</name>
@@ -657,12 +598,12 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<context>
<name>ParamControlSP</name>
<message>
<source>Enable</source>
<translation type="unfinished">Aktivieren</translation>
<source>Cancel</source>
<translation>Abbrechen</translation>
</message>
<message>
<source>Cancel</source>
<translation type="unfinished">Abbrechen</translation>
<source>Enable</source>
<translation>Aktivieren</translation>
</message>
</context>
<context>
@@ -818,40 +759,40 @@ This may take up to a minute.</source>
<name>SettingsWindowSP</name>
<message>
<source>×</source>
<translation type="unfinished">x</translation>
<translation>x</translation>
</message>
<message>
<source>Device</source>
<translation type="unfinished">Gerät</translation>
<translation>Gerät</translation>
</message>
<message>
<source>Network</source>
<translation type="unfinished">Netzwerk</translation>
<translation>Netzwerk</translation>
</message>
<message>
<source>Toggles</source>
<translation>Schalter</translation>
</message>
<message>
<source>Software</source>
<translation>Software</translation>
</message>
<message>
<source>Developer</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>sunnypilot</source>
<translation>sunnypilot</translation>
</message>
<message>
<source>sunnylink</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Toggles</source>
<translation type="unfinished">Schalter</translation>
</message>
<message>
<source>Software</source>
<translation type="unfinished">Software</translation>
</message>
<message>
<source>sunnypilot</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Trips</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Developer</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Setup</name>
@@ -1144,16 +1085,32 @@ This may take up to a minute.</source>
</context>
<context>
<name>SoftwarePanelSP</name>
<message>
<source>Current Model</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>SELECT</source>
<translation type="unfinished">AUSWÄHLEN</translation>
</message>
<message>
<source>No custom model selected!</source>
<source>Reset Calibration</source>
<translation type="unfinished">Neu kalibrieren</translation>
</message>
<message>
<source>Warning: You are on a metered connection!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Continue</source>
<translation type="unfinished">Fortsetzen</translation>
</message>
<message>
<source>on Metered</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] pending...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Current Model</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1172,6 +1129,22 @@ This may take up to a minute.</source>
<source>Downloading %1 model [%2]... (%3%)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] download failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Select a Model</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Fetching models...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Model download has started in the background.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] %3</source>
<translation type="unfinished"></translation>
@@ -1188,24 +1161,12 @@ This may take up to a minute.</source>
<source>from cache</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] download failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] pending...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Fetching models...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Use Default</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Select a Model</source>
<source>No custom model selected!</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1213,7 +1174,11 @@ This may take up to a minute.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Model download has started in the background.</source>
<source>Cancel</source>
<translation type="unfinished">Abbrechen</translation>
</message>
<message>
<source>Driving Model Selector</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1224,30 +1189,6 @@ This may take up to a minute.</source>
<source>Would you like to do that now?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reset Calibration</source>
<translation type="unfinished">Neu kalibrieren</translation>
</message>
<message>
<source>Driving Model Selector</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Warning: You are on a metered connection!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Continue</source>
<translation type="unfinished">Fortsetzen</translation>
</message>
<message>
<source>on Metered</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Cancel</source>
<translation type="unfinished">Abbrechen</translation>
</message>
</context>
<context>
<name>SshControl</name>
@@ -1306,11 +1247,11 @@ This may take up to a minute.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>🎉Welcome back! We&apos;re excited to see you&apos;ve enabled sunnylink again! 🚀</source>
<translation type="unfinished"></translation>
<source>N/A</source>
<translation type="unfinished">Nicht verfügbar</translation>
</message>
<message>
<source>👋Not going to lie, it&apos;s sad to see you disabled sunnylink 😢, but we&apos;ll be here when you&apos;re ready to come back 🎉.</source>
<source>🎉Welcome back! We&apos;re excited to see you&apos;ve enabled sunnylink again! 🚀</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1318,12 +1259,16 @@ This may take up to a minute.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>N/A</source>
<translation type="unfinished">Nicht verfügbar</translation>
<source>👋Not going to lie, it&apos;s sad to see you disabled sunnylink 😢, but we&apos;ll be here when you&apos;re ready to come back 🎉.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SunnypilotPanel</name>
<message>
<source>Customize MADS</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Modular Assistive Driving System (MADS)</source>
<translation type="unfinished"></translation>
@@ -1332,10 +1277,6 @@ This may take up to a minute.</source>
<source>Enable the beloved MADS feature. Disable toggle to revert back to stock openpilot engagement/disengagement.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Customize MADS</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>TermsPage</name>
@@ -1418,6 +1359,14 @@ This may take up to a minute.</source>
<source>Experimental mode is currently unavailable on this car since the car&apos;s stock ACC is used for longitudinal control.</source>
<translation>Der experimentelle Modus ist momentan für dieses Auto nicht verfügbar da es den eingebauten adaptiven Tempomaten des Autos benutzt.</translation>
</message>
<message>
<source>openpilot Longitudinal Control (Alpha)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Aggressive</source>
<translation type="unfinished"></translation>
@@ -1434,6 +1383,10 @@ This may take up to a minute.</source>
<source>Driving Personality</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>On this car, openpilot defaults to the car&apos;s built-in ACC instead of openpilot&apos;s longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>End-to-End Longitudinal Control</source>
<translation type="unfinished"></translation>
+147 -194
View File
@@ -124,27 +124,7 @@
<translation>Modo de maniobra longitudinal</translation>
</message>
<message>
<source>openpilot Longitudinal Control (Alpha)</source>
<translation>Control longitudinal de openpilot (fase experimental)</translation>
</message>
<message>
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
<translation>AVISO: el control longitudinal de openpilot está en fase experimental para este automóvil y desactivará el Frenado Automático de Emergencia (AEB).</translation>
</message>
<message>
<source>On this car, openpilot defaults to the car&apos;s built-in ACC instead of openpilot&apos;s longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
<translation>En este automóvil, openpilot se configura de manera predeterminada con el Autocrucero Adaptativo (ACC) incorporado en el automóvil en lugar del control longitudinal de openpilot. Habilita esta opción para cambiar al control longitudinal de openpilot. Se recomienda activar el modo experimental al habilitar el control longitudinal de openpilot (aún en fase experimental).</translation>
</message>
<message>
<source>openpilot longitudinal control may come in a future update.</source>
<translation>El control longitudinal de openpilot podrá llegar en futuras actualizaciones.</translation>
</message>
<message>
<source>Hyundai: Enable Radar Tracks</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
<source>Enables or disables the github runner service.</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -152,7 +132,11 @@
<translation type="unfinished"></translation>
</message>
<message>
<source>Enables or disables the github runner service.</source>
<source>Hyundai: Enable Radar Tracks</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
<translation type="unfinished"></translation>
</message>
</context>
@@ -309,14 +293,18 @@
<source>Training Guide</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Regulatory</source>
<translation type="unfinished">Regulador</translation>
</message>
<message>
<source>Language</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reboot</source>
<translation type="unfinished">Reiniciar</translation>
</message>
<message>
<source>Regulatory</source>
<translation type="unfinished">Regulador</translation>
</message>
<message>
<source>Are you sure you want to review the training guide?</source>
<translation type="unfinished">¿Seguro que quiere revisar la guía de entrenamiento?</translation>
@@ -329,42 +317,10 @@
<source>Select a language</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reboot</source>
<translation type="unfinished">Reiniciar</translation>
</message>
<message>
<source>Power Off</source>
<translation type="unfinished">Apagar</translation>
</message>
<message>
<source>Offroad Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Are you sure you want to exit Always Offroad mode?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Confirm</source>
<translation type="unfinished">Confirmar</translation>
</message>
<message>
<source>Are you sure you want to enter Always Offroad mode?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Disengage to Enter Always Offroad Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Exit Always Offroad</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Always Offroad</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>DriveStats</name>
@@ -455,7 +411,7 @@
</message>
<message>
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
<translation type="unfinished"></translation>
<translation type="unfinished">Nota: Para vehículos sin botón de LFA/LKAS, deshabilitar este ajuste evitará que se active el control lateral.</translation>
</message>
<message>
<source>Unified Engagement Mode (UEM)</source>
@@ -519,17 +475,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<translation>Contraseña incorrecta</translation>
</message>
</context>
<context>
<name>NetworkingSP</name>
<message>
<source>Scan</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Scanning...</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>OffroadAlert</name>
<message>
@@ -578,10 +523,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<source>openpilot detected a change in the device&apos;s mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield.</source>
<translation>openpilot detectó un cambio en la posición de montaje del dispositivo. Asegúrese de que el dispositivo esté completamente asentado en el soporte y que el soporte esté firmemente asegurado al parabrisas.</translation>
</message>
<message>
<source>sunnypilot is now in Always Offroad mode. sunnypilot won&apos;t start until Always Offroad mode is disabled. Go to &quot;Settings&quot; -&gt; &quot;Device&quot; to exit Always Offroad mode.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>OffroadHome</name>
@@ -641,7 +582,7 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
</message>
<message>
<source>Please connect to Wi-Fi to complete initial pairing</source>
<translation>Conéctese a Wi-Fi para completar el emparejamiento inicial</translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>
@@ -659,11 +600,11 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<name>ParamControlSP</name>
<message>
<source>Enable</source>
<translation type="unfinished">Activar</translation>
<translation>Activar</translation>
</message>
<message>
<source>Cancel</source>
<translation type="unfinished">Cancelar</translation>
<translation>Cancelar</translation>
</message>
</context>
<context>
@@ -820,40 +761,40 @@ Esto puede tardar un minuto.</translation>
<name>SettingsWindowSP</name>
<message>
<source>×</source>
<translation type="unfinished">×</translation>
<translation>×</translation>
</message>
<message>
<source>Device</source>
<translation type="unfinished">Dispositivo</translation>
<translation>Dispositivo</translation>
</message>
<message>
<source>Network</source>
<translation type="unfinished">Red</translation>
</message>
<message>
<source>sunnylink</source>
<translation type="unfinished"></translation>
<translation>Red</translation>
</message>
<message>
<source>Toggles</source>
<translation type="unfinished">Ajustes</translation>
<translation>Ajustes</translation>
</message>
<message>
<source>Software</source>
<translation type="unfinished">Software</translation>
<translation>Software</translation>
</message>
<message>
<source>Developer</source>
<translation>Desarrollador</translation>
</message>
<message>
<source>sunnypilot</source>
<translation type="unfinished"></translation>
<translation>sunnypilot</translation>
</message>
<message>
<source>sunnylink</source>
<translation>sunnylink</translation>
</message>
<message>
<source>Trips</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Developer</source>
<translation type="unfinished">Desarrollador</translation>
</message>
</context>
<context>
<name>Setup</name>
@@ -1044,7 +985,7 @@ Esto puede tardar un minuto.</translation>
<name>SidebarSP</name>
<message>
<source>DISABLED</source>
<translation type="unfinished"></translation>
<translation>DESHABILITADO</translation>
</message>
<message>
<source>OFFLINE</source>
@@ -1052,19 +993,19 @@ Esto puede tardar un minuto.</translation>
</message>
<message>
<source>REGIST...</source>
<translation type="unfinished"></translation>
<translation>REGIST...</translation>
</message>
<message>
<source>ONLINE</source>
<translation type="unfinished">EN LÍNEA</translation>
<translation>EN LÍNEA</translation>
</message>
<message>
<source>ERROR</source>
<translation type="unfinished">ERROR</translation>
<translation>ERROR</translation>
</message>
<message>
<source>SUNNYLINK</source>
<translation type="unfinished"></translation>
<translation>SUNNYLINK</translation>
</message>
</context>
<context>
@@ -1144,94 +1085,14 @@ Esto puede tardar un minuto.</translation>
</context>
<context>
<name>SoftwarePanelSP</name>
<message>
<source>Current Model</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>SELECT</source>
<translation type="unfinished">SELECCIONAR</translation>
</message>
<message>
<source>No custom model selected!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Driving</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Navigation</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Metadata</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Downloading %1 model [%2]... (%3%)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] %3</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>downloaded</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>ready</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>from cache</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] download failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] pending...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Fetching models...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Use Default</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Select a Model</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Default</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Model download has started in the background.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>We STRONGLY suggest you to reset calibration.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Would you like to do that now?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reset Calibration</source>
<translation type="unfinished">Formatear Calibración</translation>
</message>
<message>
<source>Driving Model Selector</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Warning: You are on a metered connection!</source>
<translation type="unfinished"></translation>
@@ -1244,10 +1105,90 @@ Esto puede tardar un minuto.</translation>
<source>on Metered</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] pending...</source>
<translation>modelo de %1 [%2] pendiente...</translation>
</message>
<message>
<source>Fetching models...</source>
<translation>Obteniendo modelos</translation>
</message>
<message>
<source>Model download has started in the background.</source>
<translation>Descarga de modelo iniciada en segundo plano.</translation>
</message>
<message>
<source>Current Model</source>
<translation>Modelo Actual</translation>
</message>
<message>
<source>Driving</source>
<translation>Conducción</translation>
</message>
<message>
<source>Navigation</source>
<translation>Navegación</translation>
</message>
<message>
<source>Metadata</source>
<translation>Metadatos</translation>
</message>
<message>
<source>Downloading %1 model [%2]... (%3%)</source>
<translation>Descargando modelo de %1 [%2]... (%3%)</translation>
</message>
<message>
<source>%1 model [%2] download failed</source>
<translation>Falló descarga modelo de %1 [%2]</translation>
</message>
<message>
<source>Select a Model</source>
<translation>Selecciona un Modelo</translation>
</message>
<message>
<source>%1 model [%2] %3</source>
<translation>Modelo de %1 [%2] %3</translation>
</message>
<message>
<source>downloaded</source>
<translation>descargado</translation>
</message>
<message>
<source>ready</source>
<translation>listo</translation>
</message>
<message>
<source>from cache</source>
<translation>desde caché</translation>
</message>
<message>
<source>Use Default</source>
<translation>Por Defecto</translation>
</message>
<message>
<source>No custom model selected!</source>
<translation>No hay ningún modelo personalizado elegido!.</translation>
</message>
<message>
<source>Default</source>
<translation>Por Defecto</translation>
</message>
<message>
<source>Cancel</source>
<translation type="unfinished">Cancelar</translation>
</message>
<message>
<source>Driving Model Selector</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>We STRONGLY suggest you to reset calibration.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Would you like to do that now?</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SshControl</name>
@@ -1299,31 +1240,35 @@ Esto puede tardar un minuto.</translation>
<name>SunnylinkPanel</name>
<message>
<source>This is the master switch, it will allow you to cutoff any sunnylink requests should you want to do that.</source>
<translation type="unfinished"></translation>
<translation>Este es el interruptor principal; te permitirá desactivar completamente cualquier connectividad de sunnylink si así lo deseas.</translation>
</message>
<message>
<source>Enable sunnylink</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>🎉Welcome back! We&apos;re excited to see you&apos;ve enabled sunnylink again! 🚀</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>👋Not going to lie, it&apos;s sad to see you disabled sunnylink 😢, but we&apos;ll be here when you&apos;re ready to come back 🎉.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Device ID</source>
<translation type="unfinished"></translation>
<translation>Habilitar sunnylink</translation>
</message>
<message>
<source>N/A</source>
<translation type="unfinished">N/A</translation>
</message>
<message>
<source>🎉Welcome back! We&apos;re excited to see you&apos;ve enabled sunnylink again! 🚀</source>
<translation>🎉¡Bienvenido de vuelta! Nos alegra que hayas reactivado sunnylink. 🚀</translation>
</message>
<message>
<source>Device ID</source>
<translation>ID del dispositivo</translation>
</message>
<message>
<source>👋Not going to lie, it&apos;s sad to see you disabled sunnylink 😢, but we&apos;ll be here when you&apos;re ready to come back 🎉.</source>
<translation>👋No te mentiremos, nos entristece que hayas desactivado sunnylink 😢. Estaremos aquí cuando estes listo para volver 🎉.</translation>
</message>
</context>
<context>
<name>SunnypilotPanel</name>
<message>
<source>Customize MADS</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Modular Assistive Driving System (MADS)</source>
<translation type="unfinished"></translation>
@@ -1332,10 +1277,6 @@ Esto puede tardar un minuto.</translation>
<source>Enable the beloved MADS feature. Disable toggle to revert back to stock openpilot engagement/disengagement.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Customize MADS</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>TermsPage</name>
@@ -1366,6 +1307,18 @@ Esto puede tardar un minuto.</translation>
<source>Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off.</source>
<translation>Utilice el sistema openpilot para acceder a un autocrucero adaptativo y asistencia al conductor para mantenerse en el carril. Se requiere su atención en todo momento para utilizar esta función. Cambiar esta configuración solo tendrá efecto con el auto apagado.</translation>
</message>
<message>
<source>openpilot Longitudinal Control (Alpha)</source>
<translation>Control longitudinal de openpilot (fase experimental)</translation>
</message>
<message>
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
<translation>AVISO: el control longitudinal de openpilot está en fase experimental para este automóvil y desactivará el Frenado Automático de Emergencia (AEB).</translation>
</message>
<message>
<source>On this car, openpilot defaults to the car&apos;s built-in ACC instead of openpilot&apos;s longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
<translation>En este automóvil, openpilot se configura de manera predeterminada con el Autocrucero Adaptativo (ACC) incorporado en el automóvil en lugar del control longitudinal de openpilot. Habilita esta opción para cambiar al control longitudinal de openpilot. Se recomienda activar el modo experimental al habilitar el control longitudinal de openpilot (aún en fase experimental).</translation>
</message>
<message>
<source>Experimental Mode</source>
<translation>Modo Experimental</translation>
+33 -84
View File
@@ -117,27 +117,11 @@
<name>DeveloperPanel</name>
<message>
<source>Joystick Debug Mode</source>
<translation>Mode débogage au joystick</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Longitudinal Maneuver Mode</source>
<translation>Mode manœuvre longitudinale</translation>
</message>
<message>
<source>openpilot Longitudinal Control (Alpha)</source>
<translation>Contrôle longitudinal openpilot (Alpha)</translation>
</message>
<message>
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
<translation>ATTENTION : le contrôle longitudinal openpilot est en alpha pour cette voiture et désactivera le freinage d&apos;urgence automatique (AEB).</translation>
</message>
<message>
<source>On this car, openpilot defaults to the car&apos;s built-in ACC instead of openpilot&apos;s longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
<translation>Sur cette voiture, openpilot utilise par défaut le régulateur de vitesse adaptatif intégré à la voiture plutôt que le contrôle longitudinal d&apos;openpilot. Activez ceci pour passer au contrôle longitudinal openpilot. Il est recommandé d&apos;activer le mode expérimental lors de l&apos;activation du contrôle longitudinal openpilot alpha.</translation>
</message>
<message>
<source>openpilot longitudinal control may come in a future update.</source>
<translation>Le contrôle longitudinal openpilot pourrait être disponible dans une future mise à jour.</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enables or disables the github runner service.</source>
@@ -292,11 +276,11 @@
</message>
<message>
<source>Pair Device</source>
<translation>Associer l&apos;appareil</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>PAIR</source>
<translation>ASSOCIER</translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>
@@ -337,34 +321,6 @@
<source>Power Off</source>
<translation type="unfinished">Éteindre</translation>
</message>
<message>
<source>Offroad Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Are you sure you want to exit Always Offroad mode?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Confirm</source>
<translation type="unfinished">Confirmer</translation>
</message>
<message>
<source>Are you sure you want to enter Always Offroad mode?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Disengage to Enter Always Offroad Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Exit Always Offroad</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Always Offroad</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>DriveStats</name>
@@ -519,21 +475,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<translation>Mot de passe incorrect</translation>
</message>
</context>
<context>
<name>NetworkingSP</name>
<message>
<source>Advanced</source>
<translation type="obsolete">Avancé</translation>
</message>
<message>
<source>Scan</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Scanning...</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>OffroadAlert</name>
<message>
@@ -582,10 +523,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<source>openpilot detected a change in the device&apos;s mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield.</source>
<translation>openpilot a détecté un changement dans la position de montage de l&apos;appareil. Assurez-vous que l&apos;appareil est totalement inséré dans le support et que le support est fermement fixé au pare-brise.</translation>
</message>
<message>
<source>sunnypilot is now in Always Offroad mode. sunnypilot won&apos;t start until Always Offroad mode is disabled. Go to &quot;Settings&quot; -&gt; &quot;Device&quot; to exit Always Offroad mode.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>OffroadHome</name>
@@ -606,23 +543,23 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<name>OnroadAlerts</name>
<message>
<source>openpilot Unavailable</source>
<translation>openpilot indisponible</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>TAKE CONTROL IMMEDIATELY</source>
<translation>REPRENEZ LE CONTRÔLE IMMÉDIATEMENT</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reboot Device</source>
<translation>Redémarrer l&apos;appareil</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Waiting to start</source>
<translation>En attente de démarrage</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>System Unresponsive</source>
<translation>Système inopérant</translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>
@@ -645,7 +582,7 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
</message>
<message>
<source>Please connect to Wi-Fi to complete initial pairing</source>
<translation>Connectez-vous au Wi-Fi pour terminer l&apos;appairage initial</translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>
@@ -698,7 +635,7 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
</message>
<message>
<source>Remote snapshots</source>
<translation>Captures à distance</translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>
@@ -749,7 +686,7 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
</message>
<message>
<source>now</source>
<translation>maintenant</translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>
@@ -790,7 +727,7 @@ Cela peut prendre jusqu&apos;à une minute.</translation>
</message>
<message>
<source>System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot.</source>
<translation>Réinitialisation système déclenchée. Appuyez sur confirmer pour effacer tout le contenu et les paramètres. Appuyez sur annuler pour reprendre le démarrage.</translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>
@@ -817,7 +754,7 @@ Cela peut prendre jusqu&apos;à une minute.</translation>
</message>
<message>
<source>Developer</source>
<translation>Dév.</translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>
@@ -844,7 +781,7 @@ Cela peut prendre jusqu&apos;à une minute.</translation>
</message>
<message>
<source>Developer</source>
<translation type="unfinished">Dév.</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>sunnypilot</source>
@@ -943,15 +880,15 @@ Cela peut prendre jusqu&apos;à une minute.</translation>
</message>
<message>
<source>Choose Software to Install</source>
<translation>Choisir le logiciel à installer</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>openpilot</source>
<translation>openpilot</translation>
<translation type="unfinished">openpilot</translation>
</message>
<message>
<source>Custom Software</source>
<translation>Logiciel personnalisé</translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>
@@ -1370,6 +1307,18 @@ Cela peut prendre jusqu&apos;à une minute.</translation>
<source>Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off.</source>
<translation>Utilisez le système openpilot pour le régulateur de vitesse adaptatif et l&apos;assistance au maintien de voie. Votre attention est requise en permanence pour utiliser cette fonctionnalité. La modification de ce paramètre prend effet lorsque la voiture est éteinte.</translation>
</message>
<message>
<source>openpilot Longitudinal Control (Alpha)</source>
<translation>Contrôle longitudinal openpilot (Alpha)</translation>
</message>
<message>
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
<translation>ATTENTION : le contrôle longitudinal openpilot est en alpha pour cette voiture et désactivera le freinage d&apos;urgence automatique (AEB).</translation>
</message>
<message>
<source>On this car, openpilot defaults to the car&apos;s built-in ACC instead of openpilot&apos;s longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
<translation>Sur cette voiture, openpilot utilise par défaut le régulateur de vitesse adaptatif intégré à la voiture plutôt que le contrôle longitudinal d&apos;openpilot. Activez ceci pour passer au contrôle longitudinal openpilot. Il est recommandé d&apos;activer le mode expérimental lors de l&apos;activation du contrôle longitudinal openpilot alpha.</translation>
</message>
<message>
<source>Experimental Mode</source>
<translation>Mode expérimental</translation>
@@ -1456,7 +1405,7 @@ Cela peut prendre jusqu&apos;à une minute.</translation>
</message>
<message>
<source>Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button.</source>
<translation>Le mode Standard est recommandé. En mode Agressif, openpilot suivra les véhicules de plus près et sera plus dynamique avec l&apos;accélérateur et le frein. En mode Détendu, openpilot maintiendra une distance plus importante avec les véhicules qui précèdent. Sur les véhicules compatibles, vous pouvez alterner entre ces personnalités à l&apos;aide du bouton de distance au volant.</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner.</source>
@@ -1464,11 +1413,11 @@ Cela peut prendre jusqu&apos;à une minute.</translation>
</message>
<message>
<source>Always-On Driver Monitoring</source>
<translation>Surveillance continue du conducteur</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable driver monitoring even when openpilot is not engaged.</source>
<translation>Activer la surveillance conducteur lorsque openpilot n&apos;est pas actif.</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable Dynamic Experimental Control</source>
+154 -207
View File
@@ -24,11 +24,11 @@
</message>
<message>
<source>Enable Tethering</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Tethering Password</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>EDIT</source>
@@ -40,23 +40,23 @@
</message>
<message>
<source>IP Address</source>
<translation>IPアドレス</translation>
<translation>IP </translation>
</message>
<message>
<source>Enable Roaming</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>APN Setting</source>
<translation>APN設定</translation>
<translation>APN </translation>
</message>
<message>
<source>Enter APN</source>
<translation>APNを入力</translation>
<translation>APN </translation>
</message>
<message>
<source>leave blank for automatic configuration</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Cellular Metered</source>
@@ -64,27 +64,27 @@
</message>
<message>
<source>Prevent large data uploads when on a metered connection</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Hidden Network</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>CONNECT</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enter SSID</source>
<translation>SSIDを入力</translation>
<translation type="unfinished">SSID </translation>
</message>
<message>
<source>Enter password</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>for &quot;%1&quot;</source>
<translation>[%1]</translation>
<translation type="unfinished">%1</translation>
</message>
</context>
<context>
@@ -102,7 +102,7 @@
<name>DeclinePage</name>
<message>
<source>You must accept the Terms and Conditions in order to use openpilot.</source>
<translation>openpilotを使用するためには利用規約に同意する必要があります</translation>
<translation>openpilot </translation>
</message>
<message>
<source>Back</source>
@@ -110,34 +110,18 @@
</message>
<message>
<source>Decline, uninstall %1</source>
<translation>(%1)</translation>
<translation> %1 </translation>
</message>
</context>
<context>
<name>DeveloperPanel</name>
<message>
<source>Joystick Debug Mode</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Longitudinal Maneuver Mode</source>
<translation></translation>
</message>
<message>
<source>openpilot Longitudinal Control (Alpha)</source>
<translation>openpilotアクセル制御(Alpha)</translation>
</message>
<message>
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
<translation>openpilotのアクセル制御はアルファ版であり(AEB)</translation>
</message>
<message>
<source>On this car, openpilot defaults to the car&apos;s built-in ACC instead of openpilot&apos;s longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
<translation>openpilotは車両内蔵のACC()使openpilotのアクセル制御は無効化されていますopenpilotに切り替えるにはこの設定を有効にしてくださいExperimentalモードを推奨します</translation>
</message>
<message>
<source>openpilot longitudinal control may come in a future update.</source>
<translation>openpilotのアクセル制御は</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enables or disables the github runner service.</source>
@@ -160,11 +144,11 @@
<name>DevicePanel</name>
<message>
<source>Dongle ID</source>
<translation>ID</translation>
<translation> (Dongle ID)</translation>
</message>
<message>
<source>N/A</source>
<translation></translation>
<translation>N/A</translation>
</message>
<message>
<source>Serial</source>
@@ -180,47 +164,47 @@
</message>
<message>
<source>Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off)</source>
<translation>(OFF時の機能です)</translation>
<translation>()</translation>
</message>
<message>
<source>Reset Calibration</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>RESET</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Are you sure you want to reset calibration?</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Review Training Guide</source>
<translation></translation>
<translation>使</translation>
</message>
<message>
<source>REVIEW</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Review the rules, features, and limitations of openpilot</source>
<translation>openpilotのルール</translation>
<translation>openpilot </translation>
</message>
<message>
<source>Are you sure you want to review the training guide?</source>
<translation></translation>
<translation>使</translation>
</message>
<message>
<source>Regulatory</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>VIEW</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Change Language</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>CHANGE</source>
@@ -236,11 +220,11 @@
</message>
<message>
<source>Power Off</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. openpilot is continuously calibrating, resetting is rarely required.</source>
<translation>openpilotの本体は左右4°5°9°</translation>
<translation>openpilotの本体は4°5°9°</translation>
</message>
<message>
<source> Your device is pointed %1° %2 and %3° %4.</source>
@@ -268,15 +252,15 @@
</message>
<message>
<source>Disengage to Reboot</source>
<translation></translation>
<translation>openpilot </translation>
</message>
<message>
<source>Are you sure you want to power off?</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Disengage to Power Off</source>
<translation></translation>
<translation>openpilot </translation>
</message>
<message>
<source>Reset</source>
@@ -284,19 +268,19 @@
</message>
<message>
<source>Review</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer.</source>
<translation>commaコネクト(connect.comma.ai)commaプライムの特典を受け取ってください</translation>
<translation> comma connect (connect.comma.ai)comma primeの特典を申請してください</translation>
</message>
<message>
<source>Pair Device</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>PAIR</source>
<translation>OK</translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>
@@ -337,34 +321,6 @@
<source>Power Off</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Offroad Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Are you sure you want to exit Always Offroad mode?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Confirm</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Are you sure you want to enter Always Offroad mode?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Disengage to Enter Always Offroad Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Exit Always Offroad</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Always Offroad</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>DriveStats</name>
@@ -397,18 +353,18 @@
<name>DriverViewWindow</name>
<message>
<source>camera starting</source>
<translation></translation>
<translation></translation>
</message>
</context>
<context>
<name>ExperimentalModeButton</name>
<message>
<source>EXPERIMENTAL MODE ON</source>
<translation>EXPERIMENTALモード</translation>
<translation></translation>
</message>
<message>
<source>CHILL MODE ON</source>
<translation>CHILLモード</translation>
<translation></translation>
</message>
</context>
<context>
@@ -423,7 +379,7 @@
</message>
<message>
<source>MAX</source>
<translation></translation>
<translation></translation>
</message>
</context>
<context>
@@ -435,7 +391,7 @@
<message numerus="yes">
<source>Need at least %n character(s)!</source>
<translation>
<numerusform>%n文字以上にして下さい</numerusform>
<numerusform>%n文字以上でお願いします</numerusform>
</translation>
</message>
</context>
@@ -443,7 +399,7 @@
<name>Installer</name>
<message>
<source>Installing...</source>
<translation>...</translation>
<translation>...</translation>
</message>
</context>
<context>
@@ -511,78 +467,58 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
</message>
<message>
<source>for &quot;%1&quot;</source>
<translation>[%1]</translation>
<translation>%1</translation>
</message>
<message>
<source>Wrong password</source>
<translation></translation>
</message>
</context>
<context>
<name>NetworkingSP</name>
<message>
<source>Advanced</source>
<translation type="obsolete"></translation>
</message>
<message>
<source>Scan</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Scanning...</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
</context>
<context>
<name>OffroadAlert</name>
<message>
<source>Immediately connect to the internet to check for updates. If you do not connect to the internet, openpilot won&apos;t engage in %1</source>
<translation>openpilotを使用できなくなります[%1]</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Connect to internet to check for updates. openpilot won&apos;t automatically start until it connects to internet to check for updates.</source>
<translation>openpilotは使用できません</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unable to download updates
%1</source>
<translation>
%1</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Taking camera snapshots. System won&apos;t start until finished.</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>An update to your device&apos;s operating system is downloading in the background. You will be prompted to update when it&apos;s ready to install.</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Device failed to register. It will not connect to or upload to comma.ai servers, and receives no support from comma.ai. If this is an official device, visit https://comma.ai/support.</source>
<translation>comma.aiのサーバーに接続したりデータをアップロードしたりできませんcomma.aiのサポートも受けられません https://comma.ai/support に問い合わせて下さい。</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>NVMe drive not mounted.</source>
<translation>SSDドライブ(NVMe)</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unsupported NVMe drive detected. Device may draw significantly more power and overheat due to the unsupported NVMe.</source>
<translation>SSDドライブ(NVMe)使</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>openpilot 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.</source>
<translation>openpilotが車両を識別できませんでしたECUが認識されていない可能性があります discord.comma.ai </translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>openpilot detected a change in the device&apos;s mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield.</source>
<translation>openpilotがデバイスの取り付け位置にずれを検出しました</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Device temperature too high. System cooling down before starting. Current internal component temperature: %1</source>
<translation>: %1</translation>
</message>
<message>
<source>sunnypilot is now in Always Offroad mode. sunnypilot won&apos;t start until Always Offroad mode is disabled. Go to &quot;Settings&quot; -&gt; &quot;Device&quot; to exit Always Offroad mode.</source>
<translation type="unfinished"></translation>
</message>
</context>
@@ -605,46 +541,46 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<name>OnroadAlerts</name>
<message>
<source>openpilot Unavailable</source>
<translation>openpilotは使用できません</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>TAKE CONTROL IMMEDIATELY</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reboot Device</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Waiting to start</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>System Unresponsive</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>PairingPopup</name>
<message>
<source>Pair your device to your comma account</source>
<translation>commaアカウントを連携して下さい</translation>
<translation> comma </translation>
</message>
<message>
<source>Go to https://connect.comma.ai on your phone</source>
<translation> https://connect.comma.ai にアクセスしてください</translation>
<translation>https://connect.comma.aiにアクセスしてください</translation>
</message>
<message>
<source>Click &quot;add new device&quot; and scan the QR code on the right</source>
<translation>add new deviceQRコードをスキャンしてください</translation>
<translation>QRコードをスキャンしてください</translation>
</message>
<message>
<source>Bookmark connect.comma.ai to your home screen to use it like an app</source>
<translation>connect.comma.aiのサイトをホーム画面に追加して使</translation>
<translation>connect.comma.ai使</translation>
</message>
<message>
<source>Please connect to Wi-Fi to complete initial pairing</source>
<translation>Wi-Fiに接続してください</translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>
@@ -655,7 +591,7 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
</message>
<message>
<source>Enable</source>
<translation></translation>
<translation></translation>
</message>
</context>
<context>
@@ -673,15 +609,15 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<name>PrimeAdWidget</name>
<message>
<source>Upgrade Now</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Become a comma prime member at connect.comma.ai</source>
<translation>connect.comma.ai </translation>
<translation>connect.comma.ai </translation>
</message>
<message>
<source>PRIME FEATURES:</source>
<translation>:</translation>
<translation></translation>
</message>
<message>
<source>Remote access</source>
@@ -689,26 +625,26 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
</message>
<message>
<source>24/7 LTE connectivity</source>
<translation>24365LTE接続</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>1 year of drive storage</source>
<translation>1</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Remote snapshots</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>PrimeUserWidget</name>
<message>
<source> SUBSCRIBED</source>
<translation> </translation>
<translation> </translation>
</message>
<message>
<source>comma prime</source>
<translation>commaプライム</translation>
<translation>comma prime</translation>
</message>
</context>
<context>
@@ -728,24 +664,24 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<message numerus="yes">
<source>%n minute(s) ago</source>
<translation>
<numerusform>%n分前</numerusform>
<numerusform>%n </numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n hour(s) ago</source>
<translation>
<numerusform>%n時間前</numerusform>
<numerusform>%n </numerusform>
</translation>
</message>
<message numerus="yes">
<source>%n day(s) ago</source>
<translation>
<numerusform>%n日前</numerusform>
<numerusform>%n </numerusform>
</translation>
</message>
<message>
<source>now</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>
@@ -776,17 +712,16 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
</message>
<message>
<source>Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device.</source>
<translation>Dataパーティションをマウントできません</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Resetting device...
This may take up to a minute.</source>
<translation>
1</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot.</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>
@@ -801,19 +736,19 @@ This may take up to a minute.</source>
</message>
<message>
<source>Network</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Toggles</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Software</source>
<translation></translation>
<translation>ソ</translation>
</message>
<message>
<source>Developer</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>
@@ -840,7 +775,7 @@ This may take up to a minute.</source>
</message>
<message>
<source>Developer</source>
<translation type="unfinished"></translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>sunnypilot</source>
@@ -859,11 +794,11 @@ This may take up to a minute.</source>
<name>Setup</name>
<message>
<source>WARNING: Low Voltage</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Power your device in a car with a harness or proceed at your own risk.</source>
<translation>使</translation>
<translation></translation>
</message>
<message>
<source>Power off</source>
@@ -879,11 +814,11 @@ This may take up to a minute.</source>
</message>
<message>
<source>Before we get on the road, lets finish installation and cover some details.</source>
<translation></translation>
<translation>使</translation>
</message>
<message>
<source>Connect to Wi-Fi</source>
<translation>Wi-Fiに接続</translation>
<translation>Wi-Fi </translation>
</message>
<message>
<source>Back</source>
@@ -891,7 +826,7 @@ This may take up to a minute.</source>
</message>
<message>
<source>Continue without Wi-Fi</source>
<translation>Wi-Fiに接続せずに続行</translation>
<translation>Wi-Fi </translation>
</message>
<message>
<source>Waiting for internet</source>
@@ -899,7 +834,7 @@ This may take up to a minute.</source>
</message>
<message>
<source>Enter URL</source>
<translation>URLの入力</translation>
<translation>URL </translation>
</message>
<message>
<source>for Custom Software</source>
@@ -911,11 +846,11 @@ This may take up to a minute.</source>
</message>
<message>
<source>Download Failed</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Ensure the entered URL is valid, and the devices internet connection is good.</source>
<translation>URLが正しいかどうか</translation>
<translation> URL </translation>
</message>
<message>
<source>Reboot device</source>
@@ -923,15 +858,15 @@ This may take up to a minute.</source>
</message>
<message>
<source>Start over</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>No custom software found at this URL.</source>
<translation>URLはカスタムソフトウェアではありません</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Something went wrong. Reboot the device.</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Select a language</source>
@@ -939,30 +874,30 @@ This may take up to a minute.</source>
</message>
<message>
<source>Choose Software to Install</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>openpilot</source>
<translation>openpilot</translation>
<translation type="unfinished">openpilot</translation>
</message>
<message>
<source>Custom Software</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SetupWidget</name>
<message>
<source>Finish Setup</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer.</source>
<translation>commaコネクト(connect.comma.ai)commaプライムの特典を受け取ってください</translation>
<translation> comma connect (connect.comma.ai)comma primeの特典を申請してください</translation>
</message>
<message>
<source>Pair device</source>
<translation></translation>
<translation></translation>
</message>
</context>
<context>
@@ -1071,7 +1006,7 @@ This may take up to a minute.</source>
<name>SoftwarePanel</name>
<message>
<source>Updates are only downloaded while the car is off.</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Current Version</source>
@@ -1123,23 +1058,23 @@ This may take up to a minute.</source>
</message>
<message>
<source>failed to check for update</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>up to date, last checked %1</source>
<translation>%1</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>DOWNLOAD</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>update available</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>never</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>
@@ -1277,7 +1212,7 @@ This may take up to a minute.</source>
</message>
<message>
<source>Username &apos;%1&apos; has no keys on GitHub</source>
<translation>%1 GitHub </translation>
<translation> %1 GitHub </translation>
</message>
<message>
<source>Request timed out</source>
@@ -1285,14 +1220,14 @@ This may take up to a minute.</source>
</message>
<message>
<source>Username &apos;%1&apos; doesn&apos;t exist on GitHub</source>
<translation>%1 GitHub </translation>
<translation> &apos;%1&apos; GitHub </translation>
</message>
</context>
<context>
<name>SshToggle</name>
<message>
<source>Enable SSH</source>
<translation>SSHの有効化</translation>
<translation>SSH </translation>
</message>
</context>
<context>
@@ -1364,19 +1299,19 @@ This may take up to a minute.</source>
</message>
<message>
<source>Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off.</source>
<translation>openpilotによるアダプティブクルーズコントロールとレーンキーアシストを利用します</translation>
<translation>openpilotによるアダプティブクルーズコントロールとレーンキーピングドライバーアシストを利用します</translation>
</message>
<message>
<source>Enable Lane Departure Warnings</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h).</source>
<translation>3150km</translation>
<translation>3150km</translation>
</message>
<message>
<source>Use Metric System</source>
<translation>使</translation>
<translation>使</translation>
</message>
<message>
<source>Display speed in km/h instead of mph.</source>
@@ -1392,7 +1327,7 @@ This may take up to a minute.</source>
</message>
<message>
<source>Disengage on Accelerator Pedal</source>
<translation></translation>
<translation> openpilot </translation>
</message>
<message>
<source>When enabled, pressing the accelerator pedal will disengage openpilot.</source>
@@ -1400,11 +1335,11 @@ This may take up to a minute.</source>
</message>
<message>
<source>Experimental Mode</source>
<translation>Experimentalモード</translation>
<translation></translation>
</message>
<message>
<source>openpilot defaults to driving in &lt;b&gt;chill mode&lt;/b&gt;. Experimental mode enables &lt;b&gt;alpha-level features&lt;/b&gt; that aren&apos;t ready for chill mode. Experimental features are listed below:</source>
<translation>openpilotは標準ではゆっくりとくつろげる運転を提供しますExperimental()</translation>
<translation>openpilotは標準ではゆっくりとくつろげる運転を提供します</translation>
</message>
<message>
<source>Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected.</source>
@@ -1416,55 +1351,67 @@ This may take up to a minute.</source>
</message>
<message>
<source>Experimental mode is currently unavailable on this car since the car&apos;s stock ACC is used for longitudinal control.</source>
<translation>ACC使Experimentalモード利用できません</translation>
<translation>ACCがアクセル制御を行うため実験モード利用することができません</translation>
</message>
<message>
<source>openpilot Longitudinal Control (Alpha)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Aggressive</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Standard</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Relaxed</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Driving Personality</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>On this car, openpilot defaults to the car&apos;s built-in ACC instead of openpilot&apos;s longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>End-to-End Longitudinal Control</source>
<translation>End-to-Endアクセル制御</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>openpilot longitudinal control may come in a future update.</source>
<translation>openpilotのアクセル制御は将来のアップデートで提供される可能性があります</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches.</source>
<translation>openpilotのアルファ版アクセル制御はExperimentalモードと共に非リリースのブランチでテストすることができます</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable the openpilot longitudinal control (alpha) toggle to allow Experimental mode.</source>
<translation>openpilotのアクセル制御機能()Experimentalモードを許可してください</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button.</source>
<translation>openpilotは先行車に近づいて追従しopenpilotは先行車から距離を取って走行します</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner.</source>
<translation>Experimentalモードのロゴが右上隅に表示されます</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Always-On Driver Monitoring</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable driver monitoring even when openpilot is not engaged.</source>
<translation>openpilotが作動していない場合でも運転者モニタリングを有効にする</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable Dynamic Experimental Control</source>
@@ -1483,11 +1430,11 @@ This may take up to a minute.</source>
</message>
<message>
<source>An operating system update is required. Connect your device to Wi-Fi for the fastest update experience. The download size is approximately 1GB.</source>
<translation>OSのアップデートが必要ですWi-Fiに接続してアップデートする事をお勧めします1GBです</translation>
<translation>Wi-Fi 1GB </translation>
</message>
<message>
<source>Connect to Wi-Fi</source>
<translation>Wi-Fiに接続</translation>
<translation>Wi-Fi </translation>
</message>
<message>
<source>Install</source>
@@ -1514,23 +1461,23 @@ This may take up to a minute.</source>
<name>WiFiPromptWidget</name>
<message>
<source>Setup Wi-Fi</source>
<translation>Wi-Fiセットアップ</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Connect to Wi-Fi to upload driving data and help improve openpilot</source>
<translation>openpilotの改善に役立てるためにWi-Fi接続してください</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Open Settings</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Ready to upload</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Training data will be pulled periodically while your device is on Wi-Fi</source>
<translation>Wi-Fiに接続されている間</translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>
@@ -1549,7 +1496,7 @@ This may take up to a minute.</source>
</message>
<message>
<source>Forget Wi-Fi Network &quot;%1&quot;?</source>
<translation>Wi-Fiネットワーク%1</translation>
<translation>Wi-Fiネットワーク%1</translation>
</message>
<message>
<source>Forget</source>
+117 -164
View File
@@ -124,27 +124,7 @@
<translation> </translation>
</message>
<message>
<source>openpilot Longitudinal Control (Alpha)</source>
<translation type="unfinished">openpilot ()</translation>
</message>
<message>
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
<translation type="unfinished">경고: openpilot (AEB) .</translation>
</message>
<message>
<source>On this car, openpilot defaults to the car&apos;s built-in ACC instead of openpilot&apos;s longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
<translation type="unfinished"> openpilot ACC로 . openpilot의 . openpilot .</translation>
</message>
<message>
<source>openpilot longitudinal control may come in a future update.</source>
<translation type="unfinished">openpilot .</translation>
</message>
<message>
<source>Hyundai: Enable Radar Tracks</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
<source>Enables or disables the github runner service.</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -152,7 +132,11 @@
<translation type="unfinished"></translation>
</message>
<message>
<source>Enables or disables the github runner service.</source>
<source>Hyundai: Enable Radar Tracks</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
<translation type="unfinished"></translation>
</message>
</context>
@@ -184,7 +168,7 @@
</message>
<message>
<source>Reset Calibration</source>
<translation></translation>
<translation> </translation>
</message>
<message>
<source>RESET</source>
@@ -196,7 +180,7 @@
</message>
<message>
<source>Review Training Guide</source>
<translation> </translation>
<translation> </translation>
</message>
<message>
<source>REVIEW</source>
@@ -288,7 +272,7 @@
</message>
<message>
<source>Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer.</source>
<translation> comma connect (connect.comma.ai) comma prime .</translation>
<translation> comma connect (connect.comma.ai) comma prime .</translation>
</message>
<message>
<source>Pair Device</source>
@@ -309,14 +293,18 @@
<source>Training Guide</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Regulatory</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Language</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reboot</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Regulatory</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Are you sure you want to review the training guide?</source>
<translation type="unfinished"> ?</translation>
@@ -329,68 +317,36 @@
<source>Select a language</source>
<translation type="unfinished"> </translation>
</message>
<message>
<source>Reboot</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Power Off</source>
<translation type="unfinished"> </translation>
</message>
<message>
<source>Offroad Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Are you sure you want to exit Always Offroad mode?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Confirm</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Are you sure you want to enter Always Offroad mode?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Disengage to Enter Always Offroad Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Exit Always Offroad</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Always Offroad</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>DriveStats</name>
<message>
<source>Drives</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<source>Hours</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<source>ALL TIME</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<source>PAST WEEK</source>
<translation type="unfinished"></translation>
<translation> </translation>
</message>
<message>
<source>KM</source>
<translation type="unfinished"></translation>
<translation>km</translation>
</message>
<message>
<source>Miles</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
</context>
<context>
@@ -452,10 +408,6 @@
<source>Toggle with Main Cruise</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unified Engagement Mode (UEM)</source>
<translation type="unfinished"></translation>
@@ -487,6 +439,10 @@ Remain Active: ALC will remain active even after the brake pedal is pressed.
Pause Steering: ALC will be paused after the brake pedal is manually pressed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MultiOptionDialog</name>
@@ -518,17 +474,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<translation> </translation>
</message>
</context>
<context>
<name>NetworkingSP</name>
<message>
<source>Scan</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Scanning...</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>OffroadAlert</name>
<message>
@@ -577,10 +522,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<source>Device temperature too high. System cooling down before starting. Current internal component temperature: %1</source>
<translation> . . : %1</translation>
</message>
<message>
<source>sunnypilot is now in Always Offroad mode. sunnypilot won&apos;t start until Always Offroad mode is disabled. Go to &quot;Settings&quot; -&gt; &quot;Device&quot; to exit Always Offroad mode.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>OffroadHome</name>
@@ -640,7 +581,7 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
</message>
<message>
<source>Please connect to Wi-Fi to complete initial pairing</source>
<translation> Wi-Fi에 .</translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>
@@ -657,12 +598,12 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<context>
<name>ParamControlSP</name>
<message>
<source>Enable</source>
<translation type="unfinished"></translation>
<source>Cancel</source>
<translation></translation>
</message>
<message>
<source>Cancel</source>
<translation type="unfinished"></translation>
<source>Enable</source>
<translation></translation>
</message>
</context>
<context>
@@ -816,40 +757,40 @@ This may take up to a minute.</source>
<name>SettingsWindowSP</name>
<message>
<source>×</source>
<translation type="unfinished">×</translation>
<translation>×</translation>
</message>
<message>
<source>Device</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<source>Network</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<source>Toggles</source>
<translation></translation>
</message>
<message>
<source>Software</source>
<translation></translation>
</message>
<message>
<source>Developer</source>
<translation></translation>
</message>
<message>
<source>sunnypilot</source>
<translation>sunnypilot</translation>
</message>
<message>
<source>sunnylink</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Toggles</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Software</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>sunnypilot</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Trips</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Developer</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Setup</name>
@@ -954,11 +895,11 @@ This may take up to a minute.</source>
</message>
<message>
<source>Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer.</source>
<translation> comma connect (connect.comma.ai) comma prime .</translation>
<translation> comma connect (connect.comma.ai) comma prime .</translation>
</message>
<message>
<source>Pair device</source>
<translation> </translation>
<translation> </translation>
</message>
</context>
<context>
@@ -1140,16 +1081,32 @@ This may take up to a minute.</source>
</context>
<context>
<name>SoftwarePanelSP</name>
<message>
<source>Current Model</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>SELECT</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>No custom model selected!</source>
<source>Reset Calibration</source>
<translation type="unfinished"> </translation>
</message>
<message>
<source>Warning: You are on a metered connection!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Continue</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>on Metered</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] pending...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Current Model</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1168,6 +1125,22 @@ This may take up to a minute.</source>
<source>Downloading %1 model [%2]... (%3%)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] download failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Select a Model</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Fetching models...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Model download has started in the background.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] %3</source>
<translation type="unfinished"></translation>
@@ -1184,24 +1157,12 @@ This may take up to a minute.</source>
<source>from cache</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] download failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] pending...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Fetching models...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Use Default</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Select a Model</source>
<source>No custom model selected!</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1209,7 +1170,11 @@ This may take up to a minute.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Model download has started in the background.</source>
<source>Cancel</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Driving Model Selector</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1220,30 +1185,6 @@ This may take up to a minute.</source>
<source>Would you like to do that now?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reset Calibration</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Driving Model Selector</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Warning: You are on a metered connection!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Continue</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>on Metered</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Cancel</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SshControl</name>
@@ -1302,11 +1243,11 @@ This may take up to a minute.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>🎉Welcome back! We&apos;re excited to see you&apos;ve enabled sunnylink again! 🚀</source>
<translation type="unfinished"></translation>
<source>N/A</source>
<translation type="unfinished">N/A</translation>
</message>
<message>
<source>👋Not going to lie, it&apos;s sad to see you disabled sunnylink 😢, but we&apos;ll be here when you&apos;re ready to come back 🎉.</source>
<source>🎉Welcome back! We&apos;re excited to see you&apos;ve enabled sunnylink again! 🚀</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1314,12 +1255,16 @@ This may take up to a minute.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>N/A</source>
<translation type="unfinished">N/A</translation>
<source>👋Not going to lie, it&apos;s sad to see you disabled sunnylink 😢, but we&apos;ll be here when you&apos;re ready to come back 🎉.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SunnypilotPanel</name>
<message>
<source>Customize MADS</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Modular Assistive Driving System (MADS)</source>
<translation type="unfinished"></translation>
@@ -1328,10 +1273,6 @@ This may take up to a minute.</source>
<source>Enable the beloved MADS feature. Disable toggle to revert back to stock openpilot engagement/disengagement.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Customize MADS</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>TermsPage</name>
@@ -1418,6 +1359,18 @@ This may take up to a minute.</source>
<source>openpilot longitudinal control may come in a future update.</source>
<translation>openpilot .</translation>
</message>
<message>
<source>openpilot Longitudinal Control (Alpha)</source>
<translation>openpilot ()</translation>
</message>
<message>
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
<translation>경고: openpilot (AEB) .</translation>
</message>
<message>
<source>On this car, openpilot defaults to the car&apos;s built-in ACC instead of openpilot&apos;s longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
<translation> openpilot ACC로 . openpilot의 . openpilot .</translation>
</message>
<message>
<source>Aggressive</source>
<translation></translation>
+112 -159
View File
@@ -124,27 +124,7 @@
<translation>Modo Longitudinal Maneuver</translation>
</message>
<message>
<source>openpilot Longitudinal Control (Alpha)</source>
<translation>Controle Longitudinal openpilot (Embrionário)</translation>
</message>
<message>
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
<translation>AVISO: o controle longitudinal openpilot está em estado embrionário para este carro e desativará a Frenagem Automática de Emergência (AEB).</translation>
</message>
<message>
<source>On this car, openpilot defaults to the car&apos;s built-in ACC instead of openpilot&apos;s longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
<translation>Neste carro, o openpilot tem como padrão o ACC embutido do carro em vez do controle longitudinal do openpilot. Habilite isso para alternar para o controle longitudinal openpilot. Recomenda-se ativar o modo Experimental ao ativar o embrionário controle longitudinal openpilot.</translation>
</message>
<message>
<source>openpilot longitudinal control may come in a future update.</source>
<translation>O controle longitudinal openpilot poderá vir em uma atualização futura.</translation>
</message>
<message>
<source>Hyundai: Enable Radar Tracks</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
<source>Enables or disables the github runner service.</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -152,7 +132,11 @@
<translation type="unfinished"></translation>
</message>
<message>
<source>Enables or disables the github runner service.</source>
<source>Hyundai: Enable Radar Tracks</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
<translation type="unfinished"></translation>
</message>
</context>
@@ -309,14 +293,18 @@
<source>Training Guide</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Regulatory</source>
<translation type="unfinished">Regulatório</translation>
</message>
<message>
<source>Language</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reboot</source>
<translation type="unfinished">Reiniciar</translation>
</message>
<message>
<source>Regulatory</source>
<translation type="unfinished">Regulatório</translation>
</message>
<message>
<source>Are you sure you want to review the training guide?</source>
<translation type="unfinished">Tem certeza que quer rever o treinamento?</translation>
@@ -329,68 +317,36 @@
<source>Select a language</source>
<translation type="unfinished">Selecione o Idioma</translation>
</message>
<message>
<source>Reboot</source>
<translation type="unfinished">Reiniciar</translation>
</message>
<message>
<source>Power Off</source>
<translation type="unfinished">Desligar</translation>
</message>
<message>
<source>Offroad Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Are you sure you want to exit Always Offroad mode?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Confirm</source>
<translation type="unfinished">Confirmar</translation>
</message>
<message>
<source>Are you sure you want to enter Always Offroad mode?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Disengage to Enter Always Offroad Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Exit Always Offroad</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Always Offroad</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>DriveStats</name>
<message>
<source>Drives</source>
<translation type="unfinished"></translation>
<translation>Dirigidas</translation>
</message>
<message>
<source>Hours</source>
<translation type="unfinished"></translation>
<translation>Horas</translation>
</message>
<message>
<source>ALL TIME</source>
<translation type="unfinished"></translation>
<translation>TOTAL</translation>
</message>
<message>
<source>PAST WEEK</source>
<translation type="unfinished"></translation>
<translation>SEMANA PASSADA</translation>
</message>
<message>
<source>KM</source>
<translation type="unfinished"></translation>
<translation>KM</translation>
</message>
<message>
<source>Miles</source>
<translation type="unfinished"></translation>
<translation>Milhas</translation>
</message>
</context>
<context>
@@ -453,10 +409,6 @@
<source>Toggle with Main Cruise</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unified Engagement Mode (UEM)</source>
<translation type="unfinished"></translation>
@@ -488,6 +440,10 @@ Remain Active: ALC will remain active even after the brake pedal is pressed.
Pause Steering: ALC will be paused after the brake pedal is manually pressed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MultiOptionDialog</name>
@@ -519,17 +475,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<translation>Senha incorreta</translation>
</message>
</context>
<context>
<name>NetworkingSP</name>
<message>
<source>Scan</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Scanning...</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>OffroadAlert</name>
<message>
@@ -578,10 +523,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<source>Device temperature too high. System cooling down before starting. Current internal component temperature: %1</source>
<translation>Temperatura do dispositivo muito alta. O sistema está sendo resfriado antes de iniciar. A temperatura atual do componente interno é: %1</translation>
</message>
<message>
<source>sunnypilot is now in Always Offroad mode. sunnypilot won&apos;t start until Always Offroad mode is disabled. Go to &quot;Settings&quot; -&gt; &quot;Device&quot; to exit Always Offroad mode.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>OffroadHome</name>
@@ -641,7 +582,7 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
</message>
<message>
<source>Please connect to Wi-Fi to complete initial pairing</source>
<translation>Por favor conecte ao Wi-Fi para completar o pareamento inicial</translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>
@@ -658,12 +599,12 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<context>
<name>ParamControlSP</name>
<message>
<source>Enable</source>
<translation type="unfinished">Ativar</translation>
<source>Cancel</source>
<translation>Cancelar</translation>
</message>
<message>
<source>Cancel</source>
<translation type="unfinished">Cancelar</translation>
<source>Enable</source>
<translation>Ativar</translation>
</message>
</context>
<context>
@@ -820,40 +761,40 @@ Isso pode levar até um minuto.</translation>
<name>SettingsWindowSP</name>
<message>
<source>×</source>
<translation type="unfinished">×</translation>
<translation>×</translation>
</message>
<message>
<source>Device</source>
<translation type="unfinished">Dispositivo</translation>
<translation>Dispositivo</translation>
</message>
<message>
<source>Network</source>
<translation type="unfinished">Rede</translation>
<translation>Rede</translation>
</message>
<message>
<source>Toggles</source>
<translation>Ajustes</translation>
</message>
<message>
<source>Software</source>
<translation>Software</translation>
</message>
<message>
<source>Developer</source>
<translation>Desenvdor</translation>
</message>
<message>
<source>sunnypilot</source>
<translation>sunnypilot</translation>
</message>
<message>
<source>sunnylink</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Toggles</source>
<translation type="unfinished">Ajustes</translation>
</message>
<message>
<source>Software</source>
<translation type="unfinished">Software</translation>
</message>
<message>
<source>sunnypilot</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Trips</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Developer</source>
<translation type="unfinished">Desenvdor</translation>
</message>
</context>
<context>
<name>Setup</name>
@@ -1144,16 +1085,32 @@ Isso pode levar até um minuto.</translation>
</context>
<context>
<name>SoftwarePanelSP</name>
<message>
<source>Current Model</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>SELECT</source>
<translation type="unfinished">SELECIONE</translation>
</message>
<message>
<source>No custom model selected!</source>
<source>Reset Calibration</source>
<translation type="unfinished">Reinicializar Calibragem</translation>
</message>
<message>
<source>Warning: You are on a metered connection!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Continue</source>
<translation type="unfinished">Continuar</translation>
</message>
<message>
<source>on Metered</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] pending...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Current Model</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1172,6 +1129,22 @@ Isso pode levar até um minuto.</translation>
<source>Downloading %1 model [%2]... (%3%)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] download failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Select a Model</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Fetching models...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Model download has started in the background.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] %3</source>
<translation type="unfinished"></translation>
@@ -1188,24 +1161,12 @@ Isso pode levar até um minuto.</translation>
<source>from cache</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] download failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] pending...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Fetching models...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Use Default</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Select a Model</source>
<source>No custom model selected!</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1213,7 +1174,11 @@ Isso pode levar até um minuto.</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Model download has started in the background.</source>
<source>Cancel</source>
<translation type="unfinished">Cancelar</translation>
</message>
<message>
<source>Driving Model Selector</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1224,30 +1189,6 @@ Isso pode levar até um minuto.</translation>
<source>Would you like to do that now?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reset Calibration</source>
<translation type="unfinished">Reinicializar Calibragem</translation>
</message>
<message>
<source>Driving Model Selector</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Warning: You are on a metered connection!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Continue</source>
<translation type="unfinished">Continuar</translation>
</message>
<message>
<source>on Metered</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Cancel</source>
<translation type="unfinished">Cancelar</translation>
</message>
</context>
<context>
<name>SshControl</name>
@@ -1306,11 +1247,11 @@ Isso pode levar até um minuto.</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>🎉Welcome back! We&apos;re excited to see you&apos;ve enabled sunnylink again! 🚀</source>
<translation type="unfinished"></translation>
<source>N/A</source>
<translation type="unfinished">N/A</translation>
</message>
<message>
<source>👋Not going to lie, it&apos;s sad to see you disabled sunnylink 😢, but we&apos;ll be here when you&apos;re ready to come back 🎉.</source>
<source>🎉Welcome back! We&apos;re excited to see you&apos;ve enabled sunnylink again! 🚀</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1318,12 +1259,16 @@ Isso pode levar até um minuto.</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>N/A</source>
<translation type="unfinished">N/A</translation>
<source>👋Not going to lie, it&apos;s sad to see you disabled sunnylink 😢, but we&apos;ll be here when you&apos;re ready to come back 🎉.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SunnypilotPanel</name>
<message>
<source>Customize MADS</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Modular Assistive Driving System (MADS)</source>
<translation type="unfinished"></translation>
@@ -1332,10 +1277,6 @@ Isso pode levar até um minuto.</translation>
<source>Enable the beloved MADS feature. Disable toggle to revert back to stock openpilot engagement/disengagement.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Customize MADS</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>TermsPage</name>
@@ -1422,6 +1363,18 @@ Isso pode levar até um minuto.</translation>
<source>openpilot longitudinal control may come in a future update.</source>
<translation>O controle longitudinal openpilot poderá vir em uma atualização futura.</translation>
</message>
<message>
<source>openpilot Longitudinal Control (Alpha)</source>
<translation>Controle Longitudinal openpilot (Embrionário)</translation>
</message>
<message>
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
<translation>AVISO: o controle longitudinal openpilot está em estado embrionário para este carro e desativará a Frenagem Automática de Emergência (AEB).</translation>
</message>
<message>
<source>On this car, openpilot defaults to the car&apos;s built-in ACC instead of openpilot&apos;s longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
<translation>Neste carro, o openpilot tem como padrão o ACC embutido do carro em vez do controle longitudinal do openpilot. Habilite isso para alternar para o controle longitudinal openpilot. Recomenda-se ativar o modo Experimental ao ativar o embrionário controle longitudinal openpilot.</translation>
</message>
<message>
<source>Aggressive</source>
<translation>Disputa</translation>
+109 -156
View File
@@ -124,27 +124,7 @@
<translation type="unfinished"></translation>
</message>
<message>
<source>openpilot Longitudinal Control (Alpha)</source>
<translation type="unfinished">/ openpilot (Alpha)</translation>
</message>
<message>
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
<translation type="unfinished">คำเตือน: การควบคุมการเร่ง/ openpilot alpha (AEB) </translation>
</message>
<message>
<source>On this car, openpilot defaults to the car&apos;s built-in ACC instead of openpilot&apos;s longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
<translation type="unfinished"> openpilot / ACC openpilot openpilot / openpilot / alpha</translation>
</message>
<message>
<source>openpilot longitudinal control may come in a future update.</source>
<translation type="unfinished">/ openpilot </translation>
</message>
<message>
<source>Hyundai: Enable Radar Tracks</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
<source>Enables or disables the github runner service.</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -152,7 +132,11 @@
<translation type="unfinished"></translation>
</message>
<message>
<source>Enables or disables the github runner service.</source>
<source>Hyundai: Enable Radar Tracks</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
<translation type="unfinished"></translation>
</message>
</context>
@@ -309,14 +293,18 @@
<source>Training Guide</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Regulatory</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Language</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reboot</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Regulatory</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Are you sure you want to review the training guide?</source>
<translation type="unfinished">?</translation>
@@ -329,68 +317,36 @@
<source>Select a language</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reboot</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Power Off</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Offroad Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Are you sure you want to exit Always Offroad mode?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Confirm</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Are you sure you want to enter Always Offroad mode?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Disengage to Enter Always Offroad Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Exit Always Offroad</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Always Offroad</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>DriveStats</name>
<message>
<source>Drives</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<source>Hours</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<source>ALL TIME</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<source>PAST WEEK</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<source>KM</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<source>Miles</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
</context>
<context>
@@ -452,10 +408,6 @@
<source>Toggle with Main Cruise</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unified Engagement Mode (UEM)</source>
<translation type="unfinished"></translation>
@@ -487,6 +439,10 @@ Remain Active: ALC will remain active even after the brake pedal is pressed.
Pause Steering: ALC will be paused after the brake pedal is manually pressed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MultiOptionDialog</name>
@@ -518,17 +474,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<translation></translation>
</message>
</context>
<context>
<name>NetworkingSP</name>
<message>
<source>Scan</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Scanning...</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>OffroadAlert</name>
<message>
@@ -577,10 +522,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<source>openpilot detected a change in the device&apos;s mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield.</source>
<translation>openpilot </translation>
</message>
<message>
<source>sunnypilot is now in Always Offroad mode. sunnypilot won&apos;t start until Always Offroad mode is disabled. Go to &quot;Settings&quot; -&gt; &quot;Device&quot; to exit Always Offroad mode.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>OffroadHome</name>
@@ -658,11 +599,11 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<name>ParamControlSP</name>
<message>
<source>Enable</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<source>Cancel</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
</context>
<context>
@@ -816,40 +757,40 @@ This may take up to a minute.</source>
<name>SettingsWindowSP</name>
<message>
<source>×</source>
<translation type="unfinished">×</translation>
<translation>×</translation>
</message>
<message>
<source>Device</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<source>Network</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<source>Toggles</source>
<translation></translation>
</message>
<message>
<source>Software</source>
<translation></translation>
</message>
<message>
<source>Developer</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>sunnypilot</source>
<translation>sunnypilot</translation>
</message>
<message>
<source>sunnylink</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Toggles</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Software</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>sunnypilot</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Trips</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Developer</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Setup</name>
@@ -1140,16 +1081,32 @@ This may take up to a minute.</source>
</context>
<context>
<name>SoftwarePanelSP</name>
<message>
<source>Current Model</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>SELECT</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>No custom model selected!</source>
<source>Reset Calibration</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Warning: You are on a metered connection!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Continue</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>on Metered</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] pending...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Current Model</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1168,6 +1125,22 @@ This may take up to a minute.</source>
<source>Downloading %1 model [%2]... (%3%)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] download failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Select a Model</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Fetching models...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Model download has started in the background.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] %3</source>
<translation type="unfinished"></translation>
@@ -1184,24 +1157,12 @@ This may take up to a minute.</source>
<source>from cache</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] download failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] pending...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Fetching models...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Use Default</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Select a Model</source>
<source>No custom model selected!</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1209,7 +1170,11 @@ This may take up to a minute.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Model download has started in the background.</source>
<source>Cancel</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Driving Model Selector</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1220,30 +1185,6 @@ This may take up to a minute.</source>
<source>Would you like to do that now?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reset Calibration</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Driving Model Selector</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Warning: You are on a metered connection!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Continue</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>on Metered</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Cancel</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SshControl</name>
@@ -1302,11 +1243,11 @@ This may take up to a minute.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>🎉Welcome back! We&apos;re excited to see you&apos;ve enabled sunnylink again! 🚀</source>
<translation type="unfinished"></translation>
<source>N/A</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>👋Not going to lie, it&apos;s sad to see you disabled sunnylink 😢, but we&apos;ll be here when you&apos;re ready to come back 🎉.</source>
<source>🎉Welcome back! We&apos;re excited to see you&apos;ve enabled sunnylink again! 🚀</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1314,12 +1255,16 @@ This may take up to a minute.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>N/A</source>
<translation type="unfinished"></translation>
<source>👋Not going to lie, it&apos;s sad to see you disabled sunnylink 😢, but we&apos;ll be here when you&apos;re ready to come back 🎉.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SunnypilotPanel</name>
<message>
<source>Customize MADS</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Modular Assistive Driving System (MADS)</source>
<translation type="unfinished"></translation>
@@ -1328,10 +1273,6 @@ This may take up to a minute.</source>
<source>Enable the beloved MADS feature. Disable toggle to revert back to stock openpilot engagement/disengagement.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Customize MADS</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>TermsPage</name>
@@ -1418,6 +1359,18 @@ This may take up to a minute.</source>
<source>openpilot longitudinal control may come in a future update.</source>
<translation>/ openpilot </translation>
</message>
<message>
<source>openpilot Longitudinal Control (Alpha)</source>
<translation>/ openpilot (Alpha)</translation>
</message>
<message>
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
<translation>คำเตือน: การควบคุมการเร่ง/ openpilot alpha (AEB) </translation>
</message>
<message>
<source>On this car, openpilot defaults to the car&apos;s built-in ACC instead of openpilot&apos;s longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
<translation> openpilot / ACC openpilot openpilot / openpilot / alpha</translation>
</message>
<message>
<source>Aggressive</source>
<translation></translation>
+103 -150
View File
@@ -124,19 +124,11 @@
<translation type="unfinished"></translation>
</message>
<message>
<source>openpilot Longitudinal Control (Alpha)</source>
<source>Enables or disables the github runner service.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>On this car, openpilot defaults to the car&apos;s built-in ACC instead of openpilot&apos;s longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>openpilot longitudinal control may come in a future update.</source>
<source>Enable GitHub runner service</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -147,14 +139,6 @@
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable GitHub runner service</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enables or disables the github runner service.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>DevicePanel</name>
@@ -309,14 +293,18 @@
<source>Training Guide</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Regulatory</source>
<translation type="unfinished">Mevzuat</translation>
</message>
<message>
<source>Language</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reboot</source>
<translation type="unfinished">Yeniden başlat</translation>
</message>
<message>
<source>Regulatory</source>
<translation type="unfinished">Mevzuat</translation>
</message>
<message>
<source>Are you sure you want to review the training guide?</source>
<translation type="unfinished">Eğitim kılavuzunu incelemek istediğinizden emin misiniz?</translation>
@@ -329,68 +317,36 @@
<source>Select a language</source>
<translation type="unfinished">Dil seçin</translation>
</message>
<message>
<source>Reboot</source>
<translation type="unfinished">Yeniden başlat</translation>
</message>
<message>
<source>Power Off</source>
<translation type="unfinished">Sistemi kapat</translation>
</message>
<message>
<source>Offroad Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Are you sure you want to exit Always Offroad mode?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Confirm</source>
<translation type="unfinished">Onayla</translation>
</message>
<message>
<source>Are you sure you want to enter Always Offroad mode?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Disengage to Enter Always Offroad Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Exit Always Offroad</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Always Offroad</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>DriveStats</name>
<message>
<source>Drives</source>
<translation type="unfinished"></translation>
<translation>Sürücüler</translation>
</message>
<message>
<source>Hours</source>
<translation type="unfinished"></translation>
<translation>Saat</translation>
</message>
<message>
<source>ALL TIME</source>
<translation type="unfinished"></translation>
<translation>TÜM ZAMANLAR</translation>
</message>
<message>
<source>PAST WEEK</source>
<translation type="unfinished"></translation>
<translation>GEÇEN HAFTA</translation>
</message>
<message>
<source>KM</source>
<translation type="unfinished"></translation>
<translation>KM</translation>
</message>
<message>
<source>Miles</source>
<translation type="unfinished"></translation>
<translation>Mil</translation>
</message>
</context>
<context>
@@ -452,10 +408,6 @@
<source>Toggle with Main Cruise</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unified Engagement Mode (UEM)</source>
<translation type="unfinished"></translation>
@@ -487,6 +439,10 @@ Remain Active: ALC will remain active even after the brake pedal is pressed.
Pause Steering: ALC will be paused after the brake pedal is manually pressed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MultiOptionDialog</name>
@@ -518,17 +474,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<translation>Yalnış parola</translation>
</message>
</context>
<context>
<name>NetworkingSP</name>
<message>
<source>Scan</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Scanning...</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>OffroadAlert</name>
<message>
@@ -576,10 +521,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<source>openpilot detected a change in the device&apos;s mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>sunnypilot is now in Always Offroad mode. sunnypilot won&apos;t start until Always Offroad mode is disabled. Go to &quot;Settings&quot; -&gt; &quot;Device&quot; to exit Always Offroad mode.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>OffroadHome</name>
@@ -814,40 +755,40 @@ This may take up to a minute.</source>
<name>SettingsWindowSP</name>
<message>
<source>×</source>
<translation type="unfinished">x</translation>
<translation>x</translation>
</message>
<message>
<source>Device</source>
<translation type="unfinished">Cihaz</translation>
<translation>Cihaz</translation>
</message>
<message>
<source>Network</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<source>Toggles</source>
<translation>Değiştirme</translation>
</message>
<message>
<source>Software</source>
<translation>Yazılım</translation>
</message>
<message>
<source>Developer</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>sunnypilot</source>
<translation>sunnypilot</translation>
</message>
<message>
<source>sunnylink</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Toggles</source>
<translation type="unfinished">Değiştirme</translation>
</message>
<message>
<source>Software</source>
<translation type="unfinished">Yazılım</translation>
</message>
<message>
<source>sunnypilot</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Trips</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Developer</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Setup</name>
@@ -1138,16 +1079,32 @@ This may take up to a minute.</source>
</context>
<context>
<name>SoftwarePanelSP</name>
<message>
<source>Current Model</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>SELECT</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>No custom model selected!</source>
<source>Reset Calibration</source>
<translation type="unfinished">Kalibrasyonu sıfırla</translation>
</message>
<message>
<source>Warning: You are on a metered connection!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Continue</source>
<translation type="unfinished">Devam et</translation>
</message>
<message>
<source>on Metered</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] pending...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Current Model</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1166,6 +1123,22 @@ This may take up to a minute.</source>
<source>Downloading %1 model [%2]... (%3%)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] download failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Select a Model</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Fetching models...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Model download has started in the background.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] %3</source>
<translation type="unfinished"></translation>
@@ -1182,24 +1155,12 @@ This may take up to a minute.</source>
<source>from cache</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] download failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] pending...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Fetching models...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Use Default</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Select a Model</source>
<source>No custom model selected!</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1207,7 +1168,11 @@ This may take up to a minute.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Model download has started in the background.</source>
<source>Cancel</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Driving Model Selector</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1218,30 +1183,6 @@ This may take up to a minute.</source>
<source>Would you like to do that now?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reset Calibration</source>
<translation type="unfinished">Kalibrasyonu sıfırla</translation>
</message>
<message>
<source>Driving Model Selector</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Warning: You are on a metered connection!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Continue</source>
<translation type="unfinished">Devam et</translation>
</message>
<message>
<source>on Metered</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Cancel</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SshControl</name>
@@ -1300,11 +1241,11 @@ This may take up to a minute.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>🎉Welcome back! We&apos;re excited to see you&apos;ve enabled sunnylink again! 🚀</source>
<translation type="unfinished"></translation>
<source>N/A</source>
<translation type="unfinished">N/A</translation>
</message>
<message>
<source>👋Not going to lie, it&apos;s sad to see you disabled sunnylink 😢, but we&apos;ll be here when you&apos;re ready to come back 🎉.</source>
<source>🎉Welcome back! We&apos;re excited to see you&apos;ve enabled sunnylink again! 🚀</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1312,12 +1253,16 @@ This may take up to a minute.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>N/A</source>
<translation type="unfinished">N/A</translation>
<source>👋Not going to lie, it&apos;s sad to see you disabled sunnylink 😢, but we&apos;ll be here when you&apos;re ready to come back 🎉.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SunnypilotPanel</name>
<message>
<source>Customize MADS</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Modular Assistive Driving System (MADS)</source>
<translation type="unfinished"></translation>
@@ -1326,10 +1271,6 @@ This may take up to a minute.</source>
<source>Enable the beloved MADS feature. Disable toggle to revert back to stock openpilot engagement/disengagement.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Customize MADS</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>TermsPage</name>
@@ -1388,6 +1329,14 @@ This may take up to a minute.</source>
<source>When enabled, pressing the accelerator pedal will disengage openpilot.</source>
<translation>Aktifleştirilirse eğer gaz pedalına basınca openpilot devre dışı kalır.</translation>
</message>
<message>
<source>openpilot Longitudinal Control (Alpha)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Experimental Mode</source>
<translation type="unfinished"></translation>
@@ -1412,6 +1361,10 @@ This may take up to a minute.</source>
<source>Driving Personality</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>On this car, openpilot defaults to the car&apos;s built-in ACC instead of openpilot&apos;s longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>openpilot defaults to driving in &lt;b&gt;chill mode&lt;/b&gt;. Experimental mode enables &lt;b&gt;alpha-level features&lt;/b&gt; that aren&apos;t ready for chill mode. Experimental features are listed below:</source>
<translation type="unfinished"></translation>
+111 -158
View File
@@ -124,27 +124,7 @@
<translation type="unfinished"></translation>
</message>
<message>
<source>openpilot Longitudinal Control (Alpha)</source>
<translation type="unfinished">openpilot纵向控制Alpha </translation>
</message>
<message>
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
<translation type="unfinished"> openpilot Alpha版本使AEB</translation>
</message>
<message>
<source>On this car, openpilot defaults to the car&apos;s built-in ACC instead of openpilot&apos;s longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
<translation type="unfinished">openpilot 使ACC openpilot openpilot openpilot Alpha Experimental mode</translation>
</message>
<message>
<source>openpilot longitudinal control may come in a future update.</source>
<translation type="unfinished">openpilot纵向控制可能会在未来的更新中提供</translation>
</message>
<message>
<source>Hyundai: Enable Radar Tracks</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
<source>Enables or disables the github runner service.</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -152,7 +132,11 @@
<translation type="unfinished"></translation>
</message>
<message>
<source>Enables or disables the github runner service.</source>
<source>Hyundai: Enable Radar Tracks</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
<translation type="unfinished"></translation>
</message>
</context>
@@ -309,14 +293,18 @@
<source>Training Guide</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Regulatory</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Language</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reboot</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Regulatory</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Are you sure you want to review the training guide?</source>
<translation type="unfinished"></translation>
@@ -329,68 +317,36 @@
<source>Select a language</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reboot</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Power Off</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Offroad Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Are you sure you want to exit Always Offroad mode?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Confirm</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Are you sure you want to enter Always Offroad mode?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Disengage to Enter Always Offroad Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Exit Always Offroad</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Always Offroad</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>DriveStats</name>
<message>
<source>Drives</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<source>Hours</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<source>ALL TIME</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<source>PAST WEEK</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<source>KM</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<source>Miles</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
</context>
<context>
@@ -452,10 +408,6 @@
<source>Toggle with Main Cruise</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unified Engagement Mode (UEM)</source>
<translation type="unfinished"></translation>
@@ -487,6 +439,10 @@ Remain Active: ALC will remain active even after the brake pedal is pressed.
Pause Steering: ALC will be paused after the brake pedal is manually pressed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MultiOptionDialog</name>
@@ -518,17 +474,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<translation></translation>
</message>
</context>
<context>
<name>NetworkingSP</name>
<message>
<source>Scan</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Scanning...</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>OffroadAlert</name>
<message>
@@ -577,10 +522,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<source>Device temperature too high. System cooling down before starting. Current internal component temperature: %1</source>
<translation>%1</translation>
</message>
<message>
<source>sunnypilot is now in Always Offroad mode. sunnypilot won&apos;t start until Always Offroad mode is disabled. Go to &quot;Settings&quot; -&gt; &quot;Device&quot; to exit Always Offroad mode.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>OffroadHome</name>
@@ -657,12 +598,12 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<context>
<name>ParamControlSP</name>
<message>
<source>Enable</source>
<translation type="unfinished"></translation>
<source>Cancel</source>
<translation></translation>
</message>
<message>
<source>Cancel</source>
<translation type="unfinished"></translation>
<source>Enable</source>
<translation></translation>
</message>
</context>
<context>
@@ -816,40 +757,40 @@ This may take up to a minute.</source>
<name>SettingsWindowSP</name>
<message>
<source>×</source>
<translation type="unfinished">×</translation>
<translation>×</translation>
</message>
<message>
<source>Device</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<source>Network</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<source>Toggles</source>
<translation></translation>
</message>
<message>
<source>Software</source>
<translation></translation>
</message>
<message>
<source>Developer</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>sunnypilot</source>
<translation>sunnypilot</translation>
</message>
<message>
<source>sunnylink</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Toggles</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Software</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>sunnypilot</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Trips</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Developer</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Setup</name>
@@ -1140,16 +1081,32 @@ This may take up to a minute.</source>
</context>
<context>
<name>SoftwarePanelSP</name>
<message>
<source>Current Model</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>SELECT</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>No custom model selected!</source>
<source>Reset Calibration</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Warning: You are on a metered connection!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Continue</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>on Metered</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] pending...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Current Model</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1168,6 +1125,22 @@ This may take up to a minute.</source>
<source>Downloading %1 model [%2]... (%3%)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] download failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Select a Model</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Fetching models...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Model download has started in the background.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] %3</source>
<translation type="unfinished"></translation>
@@ -1184,24 +1157,12 @@ This may take up to a minute.</source>
<source>from cache</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] download failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] pending...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Fetching models...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Use Default</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Select a Model</source>
<source>No custom model selected!</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1209,7 +1170,11 @@ This may take up to a minute.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Model download has started in the background.</source>
<source>Cancel</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Driving Model Selector</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1220,30 +1185,6 @@ This may take up to a minute.</source>
<source>Would you like to do that now?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reset Calibration</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Driving Model Selector</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Warning: You are on a metered connection!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Continue</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>on Metered</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Cancel</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SshControl</name>
@@ -1302,11 +1243,11 @@ This may take up to a minute.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>🎉Welcome back! We&apos;re excited to see you&apos;ve enabled sunnylink again! 🚀</source>
<translation type="unfinished"></translation>
<source>N/A</source>
<translation type="unfinished">N/A</translation>
</message>
<message>
<source>👋Not going to lie, it&apos;s sad to see you disabled sunnylink 😢, but we&apos;ll be here when you&apos;re ready to come back 🎉.</source>
<source>🎉Welcome back! We&apos;re excited to see you&apos;ve enabled sunnylink again! 🚀</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1314,12 +1255,16 @@ This may take up to a minute.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>N/A</source>
<translation type="unfinished">N/A</translation>
<source>👋Not going to lie, it&apos;s sad to see you disabled sunnylink 😢, but we&apos;ll be here when you&apos;re ready to come back 🎉.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SunnypilotPanel</name>
<message>
<source>Customize MADS</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Modular Assistive Driving System (MADS)</source>
<translation type="unfinished"></translation>
@@ -1328,10 +1273,6 @@ This may take up to a minute.</source>
<source>Enable the beloved MADS feature. Disable toggle to revert back to stock openpilot engagement/disengagement.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Customize MADS</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>TermsPage</name>
@@ -1418,6 +1359,18 @@ This may take up to a minute.</source>
<source>openpilot longitudinal control may come in a future update.</source>
<translation>openpilot纵向控制可能会在未来的更新中提供</translation>
</message>
<message>
<source>openpilot Longitudinal Control (Alpha)</source>
<translation>openpilot纵向控制Alpha </translation>
</message>
<message>
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
<translation> openpilot Alpha版本使AEB</translation>
</message>
<message>
<source>On this car, openpilot defaults to the car&apos;s built-in ACC instead of openpilot&apos;s longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
<translation>openpilot 使ACC openpilot openpilot openpilot Alpha Experimental mode</translation>
</message>
<message>
<source>Aggressive</source>
<translation></translation>
+111 -158
View File
@@ -124,27 +124,7 @@
<translation type="unfinished"></translation>
</message>
<message>
<source>openpilot Longitudinal Control (Alpha)</source>
<translation type="unfinished">openpilot (Alpha )</translation>
</message>
<message>
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
<translation type="unfinished"> openpilot Alpha 使AEB</translation>
</message>
<message>
<source>On this car, openpilot defaults to the car&apos;s built-in ACC instead of openpilot&apos;s longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
<translation type="unfinished">openpilot 使ACC openpilot openpilot openpilot Alpha Experimental mode</translation>
</message>
<message>
<source>openpilot longitudinal control may come in a future update.</source>
<translation type="unfinished">openpilot </translation>
</message>
<message>
<source>Hyundai: Enable Radar Tracks</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
<source>Enables or disables the github runner service.</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -152,7 +132,11 @@
<translation type="unfinished"></translation>
</message>
<message>
<source>Enables or disables the github runner service.</source>
<source>Hyundai: Enable Radar Tracks</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
<translation type="unfinished"></translation>
</message>
</context>
@@ -309,14 +293,18 @@
<source>Training Guide</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Regulatory</source>
<translation type="unfinished">/</translation>
</message>
<message>
<source>Language</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reboot</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Regulatory</source>
<translation type="unfinished">/</translation>
</message>
<message>
<source>Are you sure you want to review the training guide?</source>
<translation type="unfinished">使</translation>
@@ -329,68 +317,36 @@
<source>Select a language</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reboot</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Power Off</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Offroad Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Are you sure you want to exit Always Offroad mode?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Confirm</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Are you sure you want to enter Always Offroad mode?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Disengage to Enter Always Offroad Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Exit Always Offroad</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Always Offroad</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>DriveStats</name>
<message>
<source>Drives</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<source>Hours</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<source>ALL TIME</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<source>PAST WEEK</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<source>KM</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<source>Miles</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
</context>
<context>
@@ -452,10 +408,6 @@
<source>Toggle with Main Cruise</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Unified Engagement Mode (UEM)</source>
<translation type="unfinished"></translation>
@@ -487,6 +439,10 @@ Remain Active: ALC will remain active even after the brake pedal is pressed.
Pause Steering: ALC will be paused after the brake pedal is manually pressed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MultiOptionDialog</name>
@@ -518,17 +474,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<translation></translation>
</message>
</context>
<context>
<name>NetworkingSP</name>
<message>
<source>Scan</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Scanning...</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>OffroadAlert</name>
<message>
@@ -577,10 +522,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<source>Device temperature too high. System cooling down before starting. Current internal component temperature: %1</source>
<translation>%1</translation>
</message>
<message>
<source>sunnypilot is now in Always Offroad mode. sunnypilot won&apos;t start until Always Offroad mode is disabled. Go to &quot;Settings&quot; -&gt; &quot;Device&quot; to exit Always Offroad mode.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>OffroadHome</name>
@@ -657,12 +598,12 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
<context>
<name>ParamControlSP</name>
<message>
<source>Enable</source>
<translation type="unfinished"></translation>
<source>Cancel</source>
<translation></translation>
</message>
<message>
<source>Cancel</source>
<translation type="unfinished"></translation>
<source>Enable</source>
<translation></translation>
</message>
</context>
<context>
@@ -816,40 +757,40 @@ This may take up to a minute.</source>
<name>SettingsWindowSP</name>
<message>
<source>×</source>
<translation type="unfinished">×</translation>
<translation>×</translation>
</message>
<message>
<source>Device</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<source>Network</source>
<translation type="unfinished"></translation>
<translation></translation>
</message>
<message>
<source>Toggles</source>
<translation></translation>
</message>
<message>
<source>Software</source>
<translation></translation>
</message>
<message>
<source>Developer</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>sunnypilot</source>
<translation>sunnypilot</translation>
</message>
<message>
<source>sunnylink</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Toggles</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Software</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>sunnypilot</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Trips</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Developer</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Setup</name>
@@ -1140,16 +1081,32 @@ This may take up to a minute.</source>
</context>
<context>
<name>SoftwarePanelSP</name>
<message>
<source>Current Model</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>SELECT</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>No custom model selected!</source>
<source>Reset Calibration</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Warning: You are on a metered connection!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Continue</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>on Metered</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] pending...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Current Model</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1168,6 +1125,22 @@ This may take up to a minute.</source>
<source>Downloading %1 model [%2]... (%3%)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] download failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Select a Model</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Fetching models...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Model download has started in the background.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] %3</source>
<translation type="unfinished"></translation>
@@ -1184,24 +1157,12 @@ This may take up to a minute.</source>
<source>from cache</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] download failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>%1 model [%2] pending...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Fetching models...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Use Default</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Select a Model</source>
<source>No custom model selected!</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1209,7 +1170,11 @@ This may take up to a minute.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Model download has started in the background.</source>
<source>Cancel</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Driving Model Selector</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1220,30 +1185,6 @@ This may take up to a minute.</source>
<source>Would you like to do that now?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reset Calibration</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Driving Model Selector</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Warning: You are on a metered connection!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Continue</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>on Metered</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Cancel</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SshControl</name>
@@ -1302,11 +1243,11 @@ This may take up to a minute.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>🎉Welcome back! We&apos;re excited to see you&apos;ve enabled sunnylink again! 🚀</source>
<translation type="unfinished"></translation>
<source>N/A</source>
<translation type="unfinished">使</translation>
</message>
<message>
<source>👋Not going to lie, it&apos;s sad to see you disabled sunnylink 😢, but we&apos;ll be here when you&apos;re ready to come back 🎉.</source>
<source>🎉Welcome back! We&apos;re excited to see you&apos;ve enabled sunnylink again! 🚀</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1314,12 +1255,16 @@ This may take up to a minute.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>N/A</source>
<translation type="unfinished">使</translation>
<source>👋Not going to lie, it&apos;s sad to see you disabled sunnylink 😢, but we&apos;ll be here when you&apos;re ready to come back 🎉.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SunnypilotPanel</name>
<message>
<source>Customize MADS</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Modular Assistive Driving System (MADS)</source>
<translation type="unfinished"></translation>
@@ -1328,10 +1273,6 @@ This may take up to a minute.</source>
<source>Enable the beloved MADS feature. Disable toggle to revert back to stock openpilot engagement/disengagement.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Customize MADS</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>TermsPage</name>
@@ -1418,6 +1359,18 @@ This may take up to a minute.</source>
<source>openpilot longitudinal control may come in a future update.</source>
<translation>openpilot </translation>
</message>
<message>
<source>openpilot Longitudinal Control (Alpha)</source>
<translation>openpilot (Alpha )</translation>
</message>
<message>
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
<translation> openpilot Alpha 使AEB</translation>
</message>
<message>
<source>On this car, openpilot defaults to the car&apos;s built-in ACC instead of openpilot&apos;s longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
<translation>openpilot 使ACC openpilot openpilot openpilot Alpha Experimental mode</translation>
</message>
<message>
<source>Aggressive</source>
<translation></translation>
+2 -2
View File
@@ -75,8 +75,8 @@ void UIState::updateStatus() {
auto state = ss.getState();
auto state_mads = mads.getState();
if (state == cereal::SelfdriveState::OpenpilotState::PRE_ENABLED || state == cereal::SelfdriveState::OpenpilotState::OVERRIDING ||
state_mads == cereal::ModularAssistiveDrivingSystem::ModularAssistiveDrivingSystemState::PAUSED ||
state_mads == cereal::ModularAssistiveDrivingSystem::ModularAssistiveDrivingSystemState::OVERRIDING) {
state_mads == cereal::SelfdriveStateSP::ModularAssistiveDrivingSystem::ModularAssistiveDrivingSystemState::PAUSED ||
state_mads == cereal::SelfdriveStateSP::ModularAssistiveDrivingSystem::ModularAssistiveDrivingSystemState::OVERRIDING) {
status = STATUS_OVERRIDE;
} else {
if (mads.getAvailable()) {
+2 -2
View File
@@ -48,13 +48,13 @@ class MadsParams:
if pause_lateral_on_brake:
CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.DISENGAGE_LATERAL_ON_BRAKE
def set_car_specific_params(self, CP, CP_SP):
def set_car_specific_params(self, CP):
if CP.carName == "hyundai":
# TODO-SP: This should be separated from MADS module for future implementations
# Use "HyundaiLongitudinalMainCruiseToggleable" param
hyundai_cruise_main_toggleable = True
if hyundai_cruise_main_toggleable:
CP_SP.flags |= HyundaiFlagsSP.LONGITUDINAL_MAIN_CRUISE_TOGGLEABLE.value
CP.sunnypilotFlags |= HyundaiFlagsSP.LONGITUDINAL_MAIN_CRUISE_TOGGLEABLE.value
CP.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_LONG_MAIN_CRUISE_TOGGLEABLE
# MADS is currently not supported in Tesla due to lack of consistent states to engage controls
+37 -27
View File
@@ -24,7 +24,7 @@ THE SOFTWARE.
Last updated: July 29, 2024
"""
from cereal import car, log, custom
from cereal import messaging, car, log, custom
from opendbc.car.hyundai.values import HyundaiFlags
from opendbc.sunnypilot.car.hyundai.values import HyundaiFlagsSP
@@ -32,10 +32,9 @@ from opendbc.sunnypilot.car.hyundai.values import HyundaiFlagsSP
from openpilot.sunnypilot.mads.helpers import MadsParams
from openpilot.sunnypilot.mads.state import StateMachine, GEARS_ALLOW_PAUSED_SILENT
State = custom.ModularAssistiveDrivingSystem.ModularAssistiveDrivingSystemState
State = custom.SelfdriveStateSP.ModularAssistiveDrivingSystem.ModularAssistiveDrivingSystemState
ButtonType = car.CarState.ButtonEvent.Type
EventName = log.OnroadEvent.EventName
EventNameSP = custom.OnroadEventSP.EventName
SafetyModel = car.CarParams.SafetyModel
SET_SPEED_BUTTONS = (ButtonType.accelCruise, ButtonType.resumeCruise, ButtonType.decelCruise, ButtonType.setCruise)
@@ -49,15 +48,15 @@ class ModularAssistiveDrivingSystem:
self.enabled = False
self.active = False
self.available = False
self.mismatch_counter = 0
self.allow_always = False
self.selfdrive = selfdrive
self.selfdrive.enabled_prev = False
self.state_machine = StateMachine(self)
self.events = self.selfdrive.events
self.events_sp = self.selfdrive.events_sp
if self.selfdrive.CP.carName == "hyundai":
if (self.selfdrive.CP_SP.flags & HyundaiFlagsSP.HAS_LFA_BUTTON) or \
if (self.selfdrive.CP.sunnypilotFlags & HyundaiFlagsSP.HAS_LFA_BUTTON) or \
(self.selfdrive.CP.flags & HyundaiFlags.CANFD):
self.allow_always = True
@@ -71,7 +70,20 @@ class ModularAssistiveDrivingSystem:
self.main_enabled_toggle = self.mads_params.read_param("MadsMainCruiseAllowed")
self.unified_engagement_mode = self.mads_params.read_param("MadsUnifiedEngagementMode")
def update_events(self, CS: car.CarState):
def update_controls_mismatch(self, sm: messaging.SubMaster):
heartbeat_engaged = self.active if self.pause_lateral_on_brake_toggle else self.enabled
if not heartbeat_engaged:
self.mismatch_counter = 0
if heartbeat_engaged and any(not ps.controlsAllowedLat for ps in sm['pandaStates']
if ps.safetyModel not in IGNORED_SAFETY_MODES):
self.mismatch_counter += 1
if self.mismatch_counter >= 200:
self.events.add(EventName.controlsMismatchLateral)
def update_events(self, CS: car.CarState, sm: messaging.SubMaster):
def update_unified_engagement_mode():
uem_blocked = self.enabled or (self.selfdrive.enabled and self.selfdrive.enabled_prev)
if (self.unified_engagement_mode and uem_blocked) or not self.unified_engagement_mode:
@@ -80,30 +92,26 @@ class ModularAssistiveDrivingSystem:
def transition_paused_state():
if self.state_machine.state != State.paused:
self.events_sp.add(EventNameSP.silentLkasDisable)
def replace_event(old_event: int, new_event: int):
self.events.remove(old_event)
self.events_sp.add(new_event)
self.events.add(EventName.silentLkasDisable)
if not self.selfdrive.enabled and self.enabled:
if self.events.has(EventName.doorOpen):
replace_event(EventName.doorOpen, EventNameSP.silentDoorOpen)
self.events.replace(EventName.doorOpen, EventName.silentDoorOpen)
transition_paused_state()
if self.events.has(EventName.seatbeltNotLatched):
replace_event(EventName.seatbeltNotLatched, EventNameSP.silentSeatbeltNotLatched)
self.events.replace(EventName.seatbeltNotLatched, EventName.silentSeatbeltNotLatched)
transition_paused_state()
if self.events.has(EventName.wrongGear):
replace_event(EventName.wrongGear, EventNameSP.silentWrongGear)
self.events.replace(EventName.wrongGear, EventName.silentWrongGear)
transition_paused_state()
if self.events.has(EventName.reverseGear):
replace_event(EventName.reverseGear, EventNameSP.silentReverseGear)
self.events.replace(EventName.reverseGear, EventName.silentReverseGear)
transition_paused_state()
if self.events.has(EventName.brakeHold):
replace_event(EventName.brakeHold, EventNameSP.silentBrakeHold)
self.events.replace(EventName.brakeHold, EventName.silentBrakeHold)
transition_paused_state()
if self.events.has(EventName.parkBrake):
replace_event(EventName.parkBrake, EventNameSP.silentParkBrake)
self.events.replace(EventName.parkBrake, EventName.silentParkBrake)
transition_paused_state()
if self.pause_lateral_on_brake_toggle:
@@ -113,7 +121,7 @@ class ModularAssistiveDrivingSystem:
if not (self.pause_lateral_on_brake_toggle and CS.brakePressed) and \
not self.events.contains_in_list(GEARS_ALLOW_PAUSED_SILENT):
if self.state_machine.state == State.paused:
self.events_sp.add(EventNameSP.silentLkasEnable)
self.events.add(EventName.silentLkasEnable)
self.events.remove(EventName.preEnableStandstill)
self.events.remove(EventName.belowEngageSpeed)
@@ -126,25 +134,25 @@ class ModularAssistiveDrivingSystem:
else:
if self.main_enabled_toggle:
if CS.cruiseState.available and not self.selfdrive.CS_prev.cruiseState.available:
self.events_sp.add(EventNameSP.lkasEnable)
self.events.add(EventName.lkasEnable)
for be in CS.buttonEvents:
if be.type == ButtonType.cancel:
if not self.selfdrive.enabled and self.selfdrive.enabled_prev:
self.events_sp.add(EventNameSP.manualLongitudinalRequired)
self.events.add(EventName.manualLongitudinalRequired)
if be.type == ButtonType.lkas and be.pressed and (CS.cruiseState.available or self.allow_always):
if self.enabled:
if self.selfdrive.enabled:
self.events_sp.add(EventNameSP.manualSteeringRequired)
self.events.add(EventName.manualSteeringRequired)
else:
self.events_sp.add(EventNameSP.lkasDisable)
self.events.add(EventName.lkasDisable)
else:
self.events_sp.add(EventNameSP.lkasEnable)
self.events.add(EventName.lkasEnable)
if not CS.cruiseState.available:
self.events.remove(EventName.buttonEnable)
if self.selfdrive.CS_prev.cruiseState.available:
self.events_sp.add(EventNameSP.lkasDisable)
self.events.add(EventName.lkasDisable)
self.events.remove(EventName.pcmDisable)
self.events.remove(EventName.buttonCancel)
@@ -153,14 +161,16 @@ class ModularAssistiveDrivingSystem:
if not any(be.type in SET_SPEED_BUTTONS for be in CS.buttonEvents):
self.events.remove(EventName.wrongCarMode)
def update(self, CS: car.CarState):
self.update_controls_mismatch(sm)
def update(self, CS: car.CarState, sm: messaging.SubMaster):
if not self.enabled_toggle:
return
self.update_events(CS)
self.update_events(CS, sm)
if not self.selfdrive.CP.passive and self.selfdrive.initialized:
self.enabled, self.active = self.state_machine.update(self.events, self.events_sp)
self.enabled, self.active = self.state_machine.update(self.events)
# Copy of previous SelfdriveD states for MADS events handling
self.selfdrive.enabled_prev = self.selfdrive.enabled
+19 -34
View File
@@ -29,17 +29,14 @@ from openpilot.selfdrive.selfdrived.events import ET, Events
from openpilot.selfdrive.selfdrived.state import SOFT_DISABLE_TIME
from openpilot.common.realtime import DT_CTRL
from openpilot.sunnypilot.selfdrive.selfdrived.events import EventsSP
State = custom.ModularAssistiveDrivingSystem.ModularAssistiveDrivingSystemState
State = custom.SelfdriveStateSP.ModularAssistiveDrivingSystem.ModularAssistiveDrivingSystemState
EventName = log.OnroadEvent.EventName
EventNameSP = custom.OnroadEventSP.EventName
ACTIVE_STATES = (State.enabled, State.softDisabling, State.overriding)
ENABLED_STATES = (State.paused, *ACTIVE_STATES)
GEARS_ALLOW_PAUSED_SILENT = [EventNameSP.silentWrongGear, EventNameSP.silentReverseGear, EventNameSP.silentBrakeHold,
EventNameSP.silentDoorOpen, EventNameSP.silentSeatbeltNotLatched, EventNameSP.silentParkBrake]
GEARS_ALLOW_PAUSED_SILENT = [EventName.silentWrongGear, EventName.silentReverseGear, EventName.silentBrakeHold,
EventName.silentDoorOpen, EventName.silentSeatbeltNotLatched, EventName.silentParkBrake]
GEARS_ALLOW_PAUSED = [EventName.wrongGear, EventName.reverseGear, EventName.brakeHold,
EventName.doorOpen, EventName.seatbeltNotLatched, EventName.parkBrake,
*GEARS_ALLOW_PAUSED_SILENT]
@@ -52,57 +49,45 @@ class StateMachine:
self.state = State.disabled
self._events = Events()
self._events_sp = EventsSP()
def add_current_alert_types(self, alert_type):
if not self.selfdrive.enabled:
self.ss_state_machine.current_alert_types.append(alert_type)
def check_contains(self, event_type: str) -> bool:
return bool(self._events.contains(event_type) or self._events_sp.contains(event_type))
def check_contains_in_list(self, events_list: list[int]) -> bool:
return bool(self._events.contains_in_list(events_list) or self._events_sp.contains_in_list(events_list))
def update(self, events: Events, events_sp: EventsSP):
def update(self, events: Events):
# soft disable timer and current alert types are from the state machine of openpilot
# decrement the soft disable timer at every step, as it's reset on
# entrance in SOFT_DISABLING state
self._events = events
self._events_sp = events_sp
# ENABLED, SOFT DISABLING, PAUSED, OVERRIDING
if self.state != State.disabled:
# user and immediate disable always have priority in a non-disabled state
if self.check_contains(ET.USER_DISABLE):
if events_sp.has(EventNameSP.silentLkasDisable) or events_sp.has(EventNameSP.silentBrakeHold):
if events.contains(ET.USER_DISABLE):
if events.has(EventName.silentLkasDisable) or events.has(EventName.silentBrakeHold):
self.state = State.paused
else:
self.state = State.disabled
self.ss_state_machine.current_alert_types.append(ET.USER_DISABLE)
elif self.check_contains(ET.IMMEDIATE_DISABLE):
elif events.contains(ET.IMMEDIATE_DISABLE):
self.state = State.disabled
self.add_current_alert_types(ET.IMMEDIATE_DISABLE)
else:
# ENABLED
if self.state == State.enabled:
if self.check_contains(ET.SOFT_DISABLE):
if events.contains(ET.SOFT_DISABLE):
self.state = State.softDisabling
if not self.selfdrive.enabled:
self.ss_state_machine.soft_disable_timer = int(SOFT_DISABLE_TIME / DT_CTRL)
self.ss_state_machine.current_alert_types.append(ET.SOFT_DISABLE)
elif self.check_contains(ET.OVERRIDE_LATERAL):
elif events.contains(ET.OVERRIDE_LATERAL):
self.state = State.overriding
self.add_current_alert_types(ET.OVERRIDE_LATERAL)
# SOFT DISABLING
elif self.state == State.softDisabling:
if not self.check_contains(ET.SOFT_DISABLE):
if not events.contains(ET.SOFT_DISABLE):
# no more soft disabling condition, so go back to ENABLED
self.state = State.enabled
@@ -114,12 +99,12 @@ class StateMachine:
# PAUSED
elif self.state == State.paused:
if self.check_contains(ET.ENABLE):
if self.check_contains(ET.NO_ENTRY):
if events.contains(ET.ENABLE):
if events.contains(ET.NO_ENTRY):
self.add_current_alert_types(ET.NO_ENTRY)
else:
if self.check_contains(ET.OVERRIDE_LATERAL):
if events.contains(ET.OVERRIDE_LATERAL):
self.state = State.overriding
else:
self.state = State.enabled
@@ -127,26 +112,26 @@ class StateMachine:
# OVERRIDING
elif self.state == State.overriding:
if self.check_contains(ET.SOFT_DISABLE):
if events.contains(ET.SOFT_DISABLE):
self.state = State.softDisabling
if not self.selfdrive.enabled:
self.ss_state_machine.soft_disable_timer = int(SOFT_DISABLE_TIME / DT_CTRL)
self.ss_state_machine.current_alert_types.append(ET.SOFT_DISABLE)
elif not self.check_contains(ET.OVERRIDE_LATERAL):
elif not events.contains(ET.OVERRIDE_LATERAL):
self.state = State.enabled
else:
self.ss_state_machine.current_alert_types += [ET.OVERRIDE_LATERAL]
# DISABLED
elif self.state == State.disabled:
if self.check_contains(ET.ENABLE):
if self.check_contains(ET.NO_ENTRY):
if self.check_contains_in_list(GEARS_ALLOW_PAUSED):
if events.contains(ET.ENABLE):
if events.contains(ET.NO_ENTRY):
if events.contains_in_list(GEARS_ALLOW_PAUSED):
self.state = State.paused
self.add_current_alert_types(ET.NO_ENTRY)
else:
if self.check_contains(ET.OVERRIDE_LATERAL):
if events.contains(ET.OVERRIDE_LATERAL):
self.state = State.overriding
else:
self.state = State.enabled
@@ -27,14 +27,13 @@ Last updated: July 29, 2024
import pytest
from pytest_mock import MockerFixture
from cereal import custom
from cereal import log, custom
from openpilot.common.realtime import DT_CTRL
from openpilot.sunnypilot.mads.state import StateMachine, SOFT_DISABLE_TIME, GEARS_ALLOW_PAUSED
from openpilot.selfdrive.selfdrived.events import ET, NormalPermanentAlert
from openpilot.sunnypilot.selfdrive.selfdrived.events import EVENTS_SP
from openpilot.selfdrive.selfdrived.events import Events, ET, EVENTS, NormalPermanentAlert
State = custom.ModularAssistiveDrivingSystem.ModularAssistiveDrivingSystemState
EventNameSP = custom.OnroadEventSP.EventName
State = custom.SelfdriveStateSP.ModularAssistiveDrivingSystem.ModularAssistiveDrivingSystemState
EventName = log.OnroadEvent.EventName
# The event types that maintain the current state
MAINTAIN_STATES = {State.enabled: (None,), State.disabled: (None,), State.softDisabling: (ET.SOFT_DISABLE,),
@@ -48,7 +47,7 @@ def make_event(event_types):
event = {}
for ev in event_types:
event[ev] = NormalPermanentAlert("alert")
EVENTS_SP[0] = event
EVENTS[0] = event
return 0
@@ -63,93 +62,87 @@ class TestMADSStateMachine:
@pytest.fixture(autouse=True)
def setup_method(self, mocker: MockerFixture):
self.mads = MockMADS(mocker)
self.events = Events()
self.state_machine = StateMachine(self.mads)
self.events = self.state_machine._events
self.events_sp = self.state_machine._events_sp
self.mads.selfdrive.state_machine.soft_disable_timer = int(SOFT_DISABLE_TIME / DT_CTRL)
def reset(self):
self.events.clear()
self.events_sp.clear()
self.state_machine.state = State.disabled
def test_immediate_disable(self):
for state in ALL_STATES:
for et in MAINTAIN_STATES[state]:
self.events_sp.add(make_event([et, ET.IMMEDIATE_DISABLE]))
self.events.add(make_event([et, ET.IMMEDIATE_DISABLE]))
self.state_machine.state = state
self.state_machine.update(self.events, self.events_sp)
self.state_machine.update(self.events)
assert State.disabled == self.state_machine.state
self.reset()
self.events.clear()
def test_user_disable(self):
for state in ALL_STATES:
for et in MAINTAIN_STATES[state]:
self.events_sp.add(make_event([et, ET.USER_DISABLE]))
self.events.add(make_event([et, ET.USER_DISABLE]))
self.state_machine.state = state
self.state_machine.update(self.events, self.events_sp)
self.state_machine.update(self.events)
assert State.disabled == self.state_machine.state
self.reset()
self.events.clear()
def test_user_disable_to_paused(self):
paused_events = (EventNameSP.silentLkasDisable, EventNameSP.silentBrakeHold)
paused_events = (EventName.silentLkasDisable, EventName.silentBrakeHold)
for state in ALL_STATES:
for et in MAINTAIN_STATES[state]:
self.events_sp.add(make_event([et, ET.USER_DISABLE]))
self.events.add(make_event([et, ET.USER_DISABLE]))
for en in paused_events:
self.events_sp.add(en)
self.events.add(en)
self.state_machine.state = state
self.state_machine.update(self.events, self.events_sp)
final_state = State.paused if self.events_sp.has(en) and state != State.disabled else State.disabled
self.state_machine.update(self.events)
final_state = State.paused if self.events.has(en) and state != State.disabled else State.disabled
assert self.state_machine.state == final_state
self.reset()
self.events.clear()
def test_soft_disable(self):
for state in ALL_STATES:
if state == State.paused: # paused considers USER_DISABLE instead
continue
for et in MAINTAIN_STATES[state]:
self.events_sp.add(make_event([et, ET.SOFT_DISABLE]))
self.events.add(make_event([et, ET.SOFT_DISABLE]))
self.state_machine.state = state
self.state_machine.update(self.events, self.events_sp)
self.state_machine.update(self.events)
assert self.state_machine.state == State.disabled if state == State.disabled else State.softDisabling
self.reset()
self.events.clear()
def test_soft_disable_timer(self):
self.state_machine.state = State.enabled
self.events_sp.add(make_event([ET.SOFT_DISABLE]))
self.state_machine.update(self.events, self.events_sp)
self.events.add(make_event([ET.SOFT_DISABLE]))
self.state_machine.update(self.events)
for _ in range(int(SOFT_DISABLE_TIME / DT_CTRL)):
assert self.state_machine.state == State.softDisabling
self.mads.selfdrive.state_machine.soft_disable_timer -= 1
self.state_machine.update(self.events, self.events_sp)
self.state_machine.update(self.events)
assert self.state_machine.state == State.disabled
def test_no_entry(self):
for et in ENABLE_EVENT_TYPES:
self.events_sp.add(make_event([ET.NO_ENTRY, et]))
if not self.state_machine.check_contains_in_list(GEARS_ALLOW_PAUSED):
self.state_machine.update(self.events, self.events_sp)
self.events.add(make_event([ET.NO_ENTRY, et]))
if not self.events.contains_in_list(GEARS_ALLOW_PAUSED):
self.state_machine.update(self.events)
assert self.state_machine.state == State.disabled
self.reset()
self.events.clear()
def test_no_entry_paused(self):
self.state_machine.state = State.paused
self.events_sp.add(make_event([ET.NO_ENTRY]))
self.state_machine.update(self.events, self.events_sp)
self.events.add(make_event([ET.NO_ENTRY]))
self.state_machine.update(self.events)
assert self.state_machine.state == State.paused
def test_override_lateral(self):
self.state_machine.state = State.enabled
self.events_sp.add(make_event([ET.OVERRIDE_LATERAL]))
self.state_machine.update(self.events, self.events_sp)
self.events.add(make_event([ET.OVERRIDE_LATERAL]))
self.state_machine.update(self.events)
assert self.state_machine.state == State.overriding
def test_paused_to_enabled(self):
self.state_machine.state = State.paused
self.events_sp.add(make_event([ET.ENABLE]))
self.state_machine.update(self.events, self.events_sp)
self.events.add(make_event([ET.ENABLE]))
self.state_machine.update(self.events)
assert self.state_machine.state == State.enabled
def test_maintain_states(self):
@@ -157,7 +150,7 @@ class TestMADSStateMachine:
for et in MAINTAIN_STATES[state]:
self.state_machine.state = state
if et is not None:
self.events_sp.add(make_event([et]))
self.state_machine.update(self.events, self.events_sp)
self.events.add(make_event([et]))
self.state_machine.update(self.events)
assert self.state_machine.state == state
self.reset()
self.events.clear()
View File
-17
View File
@@ -1,17 +0,0 @@
from openpilot.selfdrive.modeld.constants import Meta
class Meta20hz(Meta):
ENGAGED = slice(0, 1)
# next 2, 4, 6, 8, 10 seconds
GAS_DISENGAGE = slice(1, 31, 6)
BRAKE_DISENGAGE = slice(2, 31, 6)
STEER_OVERRIDE = slice(3, 31, 6)
HARD_BRAKE_3 = slice(4, 31, 6)
HARD_BRAKE_4 = slice(5, 31, 6)
HARD_BRAKE_5 = slice(6, 31, 6)
# next 0, 2, 4, 6, 8, 10 seconds
GAS_PRESS = slice(31, 55, 4)
BRAKE_PRESS = slice(32, 55, 4)
LEFT_BLINKER = slice(33, 55, 4)
RIGHT_BLINKER = slice(34, 55, 4)
-26
View File
@@ -1,26 +0,0 @@
from openpilot.selfdrive.modeld.constants import Meta
from cereal import custom
from openpilot.sunnypilot.modeld_v2.meta_20hz import Meta20hz
from openpilot.sunnypilot.models.helpers import get_active_bundle
ModelBundle = custom.ModelManagerSP.ModelBundle
def load_meta_constants():
"""
Determines and loads the appropriate meta model class based on the metadata provided. The function checks
specific keys and conditions within the provided metadata dictionary to identify the corresponding meta
model class to return.
:param model_metadata: Dictionary containing metadata about the model. It includes
details such as input shapes, output slices, and other configurations for identifying
metadata-dependent meta model classes.
:type model_metadata: dict
:return: The appropriate meta model class (Meta, MetaSimPose, or MetaTombRaider)
based on the conditions and metadata provided.
:rtype: type
"""
if (bundle := get_active_bundle()) and bundle.is20hz:
return Meta20hz
return Meta # Default
-134
View File
@@ -1,134 +0,0 @@
import os
import pickle
from abc import ABC, abstractmethod
import numpy as np
from cereal import custom
from openpilot.selfdrive.modeld import MODEL_PATH, MODEL_PKL_PATH, METADATA_PATH
from openpilot.selfdrive.modeld.models.commonmodel_pyx import DrivingModelFrame, CLMem
from openpilot.selfdrive.modeld.runners.ort_helpers import make_onnx_cpu_runner, ORT_TYPES_TO_NP_TYPES
from openpilot.selfdrive.modeld.runners.tinygrad_helpers import qcom_tensor_from_opencl_address
from openpilot.system.hardware import TICI
from openpilot.system.hardware.hw import Paths
from openpilot.sunnypilot.models.helpers import get_active_bundle
from tinygrad.tensor import Tensor
if TICI:
os.environ['QCOM'] = '1'
SEND_RAW_PRED = os.getenv('SEND_RAW_PRED')
CUSTOM_MODEL_PATH = Paths.model_root()
ModelManager = custom.ModelManagerSP
class ModelRunner(ABC):
"""Abstract base class for model runners that defines the interface for running ML models."""
def __init__(self):
"""Initialize the model runner with paths to model and metadata files."""
metadata_path = METADATA_PATH
self.is_20hz = None
self._drive_model = None
self._metadata_model = None
if bundle := get_active_bundle():
bundle_models = {model.type.raw: model for model in bundle.models}
self._drive_model = bundle_models.get(ModelManager.Type.drive)
self._metadata_model = bundle_models.get(ModelManager.Type.metadata)
self.is_20hz = bundle.is20hz
# Override the metadata path if a metadata model is found in the active bundle
if self._metadata_model:
metadata_path = f"{CUSTOM_MODEL_PATH}/{self._metadata_model.fileName}"
with open(metadata_path, 'rb') as f:
self.model_metadata = pickle.load(f)
self.input_shapes = self.model_metadata['input_shapes']
self.output_slices = self.model_metadata['output_slices']
self.inputs: dict = {}
@abstractmethod
def prepare_inputs(self, imgs_cl: dict[str, CLMem], numpy_inputs: dict[str, np.ndarray], frames: dict[str, DrivingModelFrame]) -> dict:
"""Prepare inputs for model inference."""
raise NotImplementedError
@abstractmethod
def run_model(self):
"""Run model inference with prepared inputs."""
def slice_outputs(self, model_outputs: np.ndarray) -> dict:
"""Slice model outputs according to metadata configuration."""
parsed_outputs = {k: model_outputs[np.newaxis, v] for k, v in self.output_slices.items()}
if SEND_RAW_PRED:
parsed_outputs['raw_pred'] = model_outputs.copy()
return parsed_outputs
class TinygradRunner(ModelRunner):
"""Tinygrad implementation of model runner for TICI hardware."""
def __init__(self):
super().__init__()
model_pkl_path = MODEL_PKL_PATH
if self._drive_model:
model_pkl_path = f"{CUSTOM_MODEL_PATH}/{self._drive_model.fileName}"
assert model_pkl_path.endswith('_tinygrad.pkl'), f"Invalid model file: {model_pkl_path} for TinygradRunner"
# Load Tinygrad model
with open(model_pkl_path, "rb") as f:
try:
self.model_run = pickle.load(f)
except FileNotFoundError as e:
assert "/dev/kgsl-3d0" not in str(e), "Model was built on C3 or C3X, but is being loaded on PC"
raise
self.input_to_dtype = {}
self.input_to_device = {}
for idx, name in enumerate(self.model_run.captured.expected_names):
self.input_to_dtype[name] = self.model_run.captured.expected_st_vars_dtype_device[idx][2] # 2 is the dtype
self.input_to_device[name] = self.model_run.captured.expected_st_vars_dtype_device[idx][3] # 3 is the device
def prepare_inputs(self, imgs_cl: dict[str, CLMem], numpy_inputs: dict[str, np.ndarray], frames: dict[str, DrivingModelFrame]) -> dict:
# Initialize image tensors if not already done
for key in imgs_cl:
if TICI and key not in self.inputs:
self.inputs[key] = qcom_tensor_from_opencl_address(imgs_cl[key].mem_address, self.input_shapes[key], dtype=self.input_to_dtype[key])
elif not TICI:
shape = frames[key].buffer_from_cl(imgs_cl[key]).reshape(self.input_shapes[key])
self.inputs[key] = Tensor(shape, device=self.input_to_device[key], dtype=self.input_to_dtype[key]).realize()
# Update numpy inputs
for key, value in numpy_inputs.items():
if key not in imgs_cl:
self.inputs[key] = Tensor(value, device=self.input_to_device[key], dtype=self.input_to_dtype[key]).realize()
return self.inputs
def run_model(self):
return self.model_run(**self.inputs).numpy().flatten()
class ONNXRunner(ModelRunner):
"""ONNX implementation of model runner for non-TICI hardware."""
def __init__(self):
super().__init__()
self.runner = make_onnx_cpu_runner(MODEL_PATH)
self.input_to_nptype = {
model_input.name: ORT_TYPES_TO_NP_TYPES[model_input.type]
for model_input in self.runner.get_inputs()
}
def prepare_inputs(self, imgs_cl: dict[str, CLMem], numpy_inputs: dict[str, np.ndarray], frames: dict[str, DrivingModelFrame]) -> dict:
self.inputs = numpy_inputs
for key in imgs_cl:
self.inputs[key] = frames[key].buffer_from_cl(imgs_cl[key]).reshape(self.input_shapes[key]).astype(dtype=self.input_to_nptype[key])
return self.inputs
def run_model(self):
return self.runner.run(None, self.inputs)[0].flatten()
+2 -1
View File
@@ -72,12 +72,13 @@ class ModelParser:
model_bundle.generation = int(value["generation"])
model_bundle.environment = value["environment"]
model_bundle.runner = value.get("runner", custom.ModelManagerSP.Runner.snpe)
model_bundle.is20hz = value.get("is_20hz", False)
return model_bundle
@staticmethod
def parse_models(json_data: dict) -> list[custom.ModelManagerSP.ModelBundle]:
# TODO-SP: Remove the following filter once we add support for tinygrad model switcher
json_data = {k: v for k, v in json_data.items() if v.get("runner", -1) == custom.ModelManagerSP.Runner.snpe}
return [ModelParser._parse_bundle(key, value) for key, value in json_data.items()]
@@ -0,0 +1,32 @@
"""
Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
This file is part of sunnypilot and is licensed under the MIT License.
See the LICENSE.md file in the root directory for more details.
"""
from cereal import car, log
ButtonType = car.CarState.ButtonEvent.Type
EventName = log.OnroadEvent.EventName
class ButtonHoldTracker:
def __init__(self):
self.button_frame_counts = {}
def update(self, CS) -> None:
if CS.cruiseState.available:
self.update_button_timers(CS)
def update_button_timers(self, CS) -> None:
for button_type, held_frames in self.button_frame_counts.items():
if held_frames > 0:
self.button_frame_counts[button_type] += 1
for event in CS.buttonEvents:
event_type = event.type.raw
if not (event.pressed and self.button_frame_counts.get(event_type, 0) > 0): # No need to reset if the button is "pulsing" always "pressed"
self.button_frame_counts[event_type] = int(event.pressed)
def get_hold_duration(self, button_type):
return self.button_frame_counts.get(button_type, 0)
+5 -5
View File
@@ -5,12 +5,12 @@ This file is part of sunnypilot and is licensed under the MIT License.
See the LICENSE.md file in the root directory for more details.
"""
from cereal import custom
from cereal import log
from opendbc.car import structs
from openpilot.sunnypilot.selfdrive.selfdrived.events import EventsSP
from openpilot.selfdrive.selfdrived.events import Events
EventNameSP = custom.OnroadEventSP.EventName
EventName = log.OnroadEvent.EventName
class CarSpecificEventsSP:
@@ -26,9 +26,9 @@ class CarSpecificEventsSP:
self.hyundai_radar_tracks_confirmed = self.params.get_bool("HyundaiRadarTracksConfirmed")
def update(self):
events = EventsSP()
events = Events()
if self.CP.carName == 'hyundai':
if self.hyundai_radar_tracks and not self.hyundai_radar_tracks_confirmed:
events.add(EventNameSP.hyundaiRadarTracksConfirmed)
events.add(EventName.hyundaiRadarTracksConfirmed)
return events
@@ -1,50 +0,0 @@
"""
Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
This file is part of sunnypilot and is licensed under the MIT License.
See the LICENSE.md file in the root directory for more details.
"""
from cereal import car, custom
from opendbc.car import structs
from openpilot.common.params import Params
ButtonType = car.CarState.ButtonEvent.Type
EventNameSP = custom.OnroadEventSP.EventName
DISTANCE_LONG_PRESS = 50
class CruiseHelper:
def __init__(self, CP: structs.CarParams):
self.CP = CP
self.params = Params()
self.button_frame_counts = {ButtonType.gapAdjustCruise: 0}
self._experimental_mode = False
self.experimental_mode_switched = False
def update(self, CS, events, experimental_mode) -> None:
if self.CP.openpilotLongitudinalControl:
if CS.cruiseState.available:
self.update_button_frame_counts(CS)
# toggle experimental mode once on distance button hold
self.update_experimental_mode(events, experimental_mode)
def update_button_frame_counts(self, CS) -> None:
for button in self.button_frame_counts:
if self.button_frame_counts[button] > 0:
self.button_frame_counts[button] += 1
for button_event in CS.buttonEvents:
button = button_event.type.raw
if button in self.button_frame_counts:
self.button_frame_counts[button] = int(button_event.pressed)
def update_experimental_mode(self, events, experimental_mode) -> None:
if self.button_frame_counts[ButtonType.gapAdjustCruise] >= DISTANCE_LONG_PRESS and not self.experimental_mode_switched:
self._experimental_mode = not experimental_mode
self.params.put_bool_nonblocking("ExperimentalMode", self._experimental_mode)
events.add(EventNameSP.experimentalModeSwitched)
self.experimental_mode_switched = True
@@ -0,0 +1,30 @@
"""
Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
This file is part of sunnypilot and is licensed under the MIT License.
See the LICENSE.md file in the root directory for more details.
"""
from openpilot.sunnypilot.selfdrive.car.button_hold_tracker import ButtonHoldTracker, ButtonType, EventName
DISTANCE_LONG_PRESS = 50
class ExperimentalSwitcher:
def __init__(self, params, button_type=ButtonType.gapAdjustCruise):
self.params = params
self.button_type = button_type
self._button_tracker = ButtonHoldTracker()
self.experimental_mode_switched = False # Meant to be toggled off by this class's children.
def update(self, CS, events, experimental_mode):
self._button_tracker.update(CS)
if CS.cruiseState.available:
self.update_mode(events, experimental_mode)
def update_mode(self, events, experimental_mode) -> None:
if self._button_tracker.get_hold_duration(self.button_type) >= DISTANCE_LONG_PRESS and not self.experimental_mode_switched:
experimental_mode = not experimental_mode
self.params.put_bool_nonblocking("ExperimentalMode", experimental_mode)
events.add(EventName.experimentalModeSwitched)
self.experimental_mode_switched = True
+4 -5
View File
@@ -22,21 +22,20 @@ def log_fingerprint(CP: structs.CarParams) -> None:
sentry.capture_fingerprint(CP.carFingerprint, CP.carName)
def setup_car_interface_sp(CP: structs.CarParams, CP_SP: structs.CarParamsSP, params):
def setup_car_interface_sp(CP: structs.CarParams, params):
if CP.carName == 'hyundai':
if CP.flags & HyundaiFlags.MANDO_RADAR and CP.radarUnavailable:
# Having this automatic without a toggle causes a weird process replay diff because
# somehow it sees fewer logs than intended
if params.get_bool("HyundaiRadarTracksToggle"):
CP_SP.flags |= HyundaiFlagsSP.ENABLE_RADAR_TRACKS.value
CP.sunnypilotFlags |= HyundaiFlagsSP.ENABLE_RADAR_TRACKS.value
if params.get_bool("HyundaiRadarTracks"):
CP.radarUnavailable = False
def initialize_car_interface_sp(CP: structs.CarParams, CP_SP: structs.CarParamsSP, params, can_recv: CanRecvCallable,
can_send: CanSendCallable):
def initialize_car_interface_sp(CP: structs.CarParams, params, can_recv: CanRecvCallable, can_send: CanSendCallable):
if CP.carName == 'hyundai':
if CP_SP.flags & HyundaiFlagsSP.ENABLE_RADAR_TRACKS:
if CP.sunnypilotFlags & HyundaiFlagsSP.ENABLE_RADAR_TRACKS:
can_recv()
_, fingerprint = can_fingerprint(can_recv)
radar_unavailable = RADAR_START_ADDR not in fingerprint[1] or Bus.radar not in HYUNDAI_DBC[CP.carFingerprint]
@@ -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.
"""
import pytest
from cereal import car
from sunnypilot.selfdrive.car.button_hold_tracker import ButtonHoldTracker, ButtonType
@pytest.fixture
def setup_button_tracker():
return ButtonHoldTracker()
class TestButtonHoldTracker:
@pytest.mark.parametrize(
"button_type, button_events, initial_timer, expected_timer",
[
# Basic button press scenarios
(ButtonType.gapAdjustCruise, [car.CarState.ButtonEvent(type=ButtonType.gapAdjustCruise, pressed=True)], 0, 1),
(ButtonType.gapAdjustCruise, [car.CarState.ButtonEvent(type=ButtonType.gapAdjustCruise, pressed=False)], 1, 0),
# Auto-increment when already held
(ButtonType.gapAdjustCruise, [], 5, 6),
(ButtonType.cancel, [], 10, 11),
(ButtonType.leftBlinker, [], 1, 2),
# Multiple button events in same frame
(ButtonType.gapAdjustCruise,
[
car.CarState.ButtonEvent(type=ButtonType.cancel, pressed=True),
car.CarState.ButtonEvent(type=ButtonType.gapAdjustCruise, pressed=False)
], 0, 0),
# Events for different buttons shouldn't affect each other
(ButtonType.gapAdjustCruise, [car.CarState.ButtonEvent(type=ButtonType.cancel, pressed=True)], 5, 6),
# Press while already held (like if it was pulsing the event for some reason)
(ButtonType.cancel, [car.CarState.ButtonEvent(type=ButtonType.cancel, pressed=True)], 5, 6),
# Edge cases
(ButtonType.leftBlinker, [], 0, 0),
(ButtonType.cancel, [car.CarState.ButtonEvent(type=ButtonType.cancel, pressed=False)], 0, 0),
],
ids=[
"initial_button_press",
"button_release",
"increment_held_gap_adjust",
"increment_held_cancel",
"increment_held_blinker",
"multiple_events_same_frame",
"different_button_no_effect",
"press_while_held",
"zero_state_no_events",
"release_when_not_held"
]
)
def test_update_button_timers(self, mocker, setup_button_tracker, button_type, button_events, initial_timer, expected_timer):
tracker = setup_button_tracker
mock_CS = mocker.Mock(buttonEvents=button_events, cruiseState=mocker.Mock(available=True))
if initial_timer > 0:
tracker.button_frame_counts[button_type] = initial_timer
tracker.update(mock_CS)
timer_value = tracker.get_hold_duration(button_type)
assert timer_value == expected_timer, f"Expected timer for {button_type} to be {expected_timer}, but got {timer_value}"
def test_cruise_state_unavailable(self, mocker, setup_button_tracker):
tracker = setup_button_tracker
mock_CS = mocker.Mock(
buttonEvents=[car.CarState.ButtonEvent(type=ButtonType.gapAdjustCruise, pressed=True)],
cruiseState=mocker.Mock(available=False)
)
tracker.update(mock_CS)
assert tracker.get_hold_duration(ButtonType.gapAdjustCruise) == 0
@@ -1,66 +0,0 @@
from parameterized import parameterized_class
from cereal import car
from openpilot.selfdrive.selfdrived.events import Events
from openpilot.sunnypilot.selfdrive.car.cruise_helpers import CruiseHelper, DISTANCE_LONG_PRESS
ButtonEvent = car.CarState.ButtonEvent
ButtonType = car.CarState.ButtonEvent.Type
@parameterized_class(('openpilot_longitudinal',), [(True,)])
class TestCruiseHelper:
def setup_method(self):
self.CP = car.CarParams(openpilotLongitudinalControl=self.openpilot_longitudinal)
self.cruise_helper = CruiseHelper(self.CP)
self.cruise_helper.experimental_mode_switched = False
self.events = Events()
def reset(self):
for _ in range(2):
CS = car.CarState(cruiseState={"available": False})
CS.buttonEvents = [ButtonEvent(type=ButtonType.gapAdjustCruise, pressed=False)]
self.cruise_helper._experimental_mode = False
self.cruise_helper.experimental_mode_switched = False
self.cruise_helper.update(CS, self.events, False)
def test_gap_adjust_cruise_long_press_toggle_mode(self) -> None:
for pressed in (True, False):
for experimental_mode in (True, False):
self.reset()
self.cruise_helper._experimental_mode = experimental_mode
toggled_mode = not experimental_mode if pressed else experimental_mode
for i in range(DISTANCE_LONG_PRESS):
CS = car.CarState(cruiseState={"available": True})
CS.buttonEvents = [ButtonEvent(type=ButtonType.gapAdjustCruise, pressed=pressed)] if i == 0 else []
self.cruise_helper.update(CS, self.events, experimental_mode)
# mode should be toggled
assert self.cruise_helper._experimental_mode == toggled_mode
assert self.cruise_helper.experimental_mode_switched is pressed
# keep holding button after switching mode
for _ in range(DISTANCE_LONG_PRESS):
CS = car.CarState(cruiseState={"available": True})
CS.buttonEvents = [ButtonEvent(type=ButtonType.gapAdjustCruise, pressed=pressed)]
self.cruise_helper.update(CS, self.events, toggled_mode)
# mode should not be toggled
assert self.cruise_helper._experimental_mode == toggled_mode
assert self.cruise_helper.experimental_mode_switched is pressed
def test_gap_adjust_cruise_short_press_toggle_mode(self) -> None:
for pressed in (True, False):
for experimental_mode in (True, False):
self.reset()
self.cruise_helper._experimental_mode = experimental_mode
for i in range(DISTANCE_LONG_PRESS - 1):
CS = car.CarState(cruiseState={"available": True})
CS.buttonEvents = [ButtonEvent(type=ButtonType.gapAdjustCruise, pressed=pressed)] if i == 0 else []
self.cruise_helper.update(CS, self.events, experimental_mode)
# mode should not be toggled
assert self.cruise_helper._experimental_mode == experimental_mode
assert self.cruise_helper.experimental_mode_switched is False
@@ -0,0 +1,55 @@
"""
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.
"""
import pytest
from cereal import car
from sunnypilot.selfdrive.car.experimental_switcher import ExperimentalSwitcher, ButtonType, EventName, DISTANCE_LONG_PRESS
@pytest.fixture
def setup_switcher(mocker):
mock_params = mocker.Mock()
return ExperimentalSwitcher(mock_params), mock_params
class TestExperimentalSwitcher:
@pytest.mark.parametrize(
"use_experimental_mode, long_press, expected_mode, expected_experimental_mode",
[
(False, True, True, True), # Normal -> Experimental via long press
(True, True, False, True), # Experimental -> Normal via long press
(False, False, False, False) # No change without long press
],
ids=[
"enable_experimental_mode",
"disable_experimental_mode",
"no_mode_change_without_long_press"
]
)
def test_update_mode_switches(self, mocker, setup_switcher, use_experimental_mode, long_press, expected_mode, expected_experimental_mode):
switcher, params = setup_switcher
mock_events = mocker.Mock()
mock_CS = mocker.Mock(
buttonEvents=[car.CarState.ButtonEvent(type=ButtonType.gapAdjustCruise, pressed=True)],
cruiseState=mocker.Mock(available=True)
)
if long_press:
for _ in range(DISTANCE_LONG_PRESS + 1):
switcher.update(mock_CS, mock_events, use_experimental_mode)
switcher.update_mode(mock_events, use_experimental_mode)
if expected_experimental_mode:
params.put_bool_nonblocking.assert_called_once_with("ExperimentalMode", expected_mode)
mock_events.add.assert_called_once_with(EventName.experimentalModeSwitched)
assert switcher.experimental_mode_switched is True
else:
params.put_bool_nonblocking.assert_not_called()
mock_events.add.assert_not_called()
assert switcher.experimental_mode_switched is False
-133
View File
@@ -1,133 +0,0 @@
from cereal import log, car, custom
from openpilot.sunnypilot.selfdrive.selfdrived.events_base import EventsBase, Priority, ET, Alert, \
NoEntryAlert, ImmediateDisableAlert, EngagementAlert, NormalPermanentAlert, AlertCallbackType
AlertSize = log.SelfdriveState.AlertSize
AlertStatus = log.SelfdriveState.AlertStatus
VisualAlert = car.CarControl.HUDControl.VisualAlert
AudibleAlert = car.CarControl.HUDControl.AudibleAlert
EventNameSP = custom.OnroadEventSP.EventName
# get event name from enum
EVENT_NAME_SP = {v: k for k, v in EventNameSP.schema.enumerants.items()}
class EventsSP(EventsBase):
def __init__(self):
super().__init__()
self.event_counters = dict.fromkeys(EVENTS_SP.keys(), 0)
def get_events_mapping(self) -> dict[int, dict[str, Alert | AlertCallbackType]]:
return EVENTS_SP
def get_event_name(self, event: int):
return EVENT_NAME_SP[event]
def get_event_msg_type(self):
return custom.OnroadEventSP
EVENTS_SP: dict[int, dict[str, Alert | AlertCallbackType]] = {
# sunnypilot
EventNameSP.lkasEnable: {
ET.ENABLE: EngagementAlert(AudibleAlert.engage),
},
EventNameSP.lkasDisable: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
},
EventNameSP.manualSteeringRequired: {
ET.USER_DISABLE: Alert(
"Automatic Lane Centering is OFF",
"Manual Steering Required",
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.disengage, 1.),
},
EventNameSP.manualLongitudinalRequired: {
ET.WARNING: Alert(
"Smart/Adaptive Cruise Control: OFF",
"Manual Speed Control Required",
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.none, 1.),
},
EventNameSP.silentLkasEnable: {
ET.ENABLE: EngagementAlert(AudibleAlert.none),
},
EventNameSP.silentLkasDisable: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.none),
},
EventNameSP.silentBrakeHold: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.none),
ET.NO_ENTRY: NoEntryAlert("Brake Hold Active"),
},
EventNameSP.silentWrongGear: {
ET.WARNING: Alert(
"",
"",
AlertStatus.normal, AlertSize.none,
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, 0.),
ET.NO_ENTRY: Alert(
"Gear not D",
"openpilot Unavailable",
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.none, 0.),
},
EventNameSP.silentReverseGear: {
ET.PERMANENT: Alert(
"Reverse\nGear",
"",
AlertStatus.normal, AlertSize.full,
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .2, creation_delay=0.5),
ET.NO_ENTRY: NoEntryAlert("Reverse Gear"),
},
EventNameSP.silentDoorOpen: {
ET.WARNING: Alert(
"",
"",
AlertStatus.normal, AlertSize.none,
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, 0.),
ET.NO_ENTRY: NoEntryAlert("Door Open"),
},
EventNameSP.silentSeatbeltNotLatched: {
ET.WARNING: Alert(
"",
"",
AlertStatus.normal, AlertSize.none,
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, 0.),
ET.NO_ENTRY: NoEntryAlert("Seatbelt Unlatched"),
},
EventNameSP.silentParkBrake: {
ET.WARNING: Alert(
"",
"",
AlertStatus.normal, AlertSize.none,
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, 0.),
ET.NO_ENTRY: NoEntryAlert("Parking Brake Engaged"),
},
EventNameSP.controlsMismatchLateral: {
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Controls Mismatch: Lateral"),
ET.NO_ENTRY: NoEntryAlert("Controls Mismatch: Lateral"),
},
EventNameSP.hyundaiRadarTracksConfirmed: {
ET.PERMANENT: NormalPermanentAlert("Radar tracks available. Restart the car to initialize")
},
EventNameSP.experimentalModeSwitched: {
ET.WARNING: NormalPermanentAlert("Experimental Mode Switched", duration=1.5)
}
}
@@ -1,225 +0,0 @@
import bisect
from enum import IntEnum
from abc import abstractmethod
from collections.abc import Callable
from cereal import log, car
import cereal.messaging as messaging
from openpilot.common.realtime import DT_CTRL
AlertSize = log.SelfdriveState.AlertSize
AlertStatus = log.SelfdriveState.AlertStatus
VisualAlert = car.CarControl.HUDControl.VisualAlert
AudibleAlert = car.CarControl.HUDControl.AudibleAlert
# Alert priorities
class Priority(IntEnum):
LOWEST = 0
LOWER = 1
LOW = 2
MID = 3
HIGH = 4
HIGHEST = 5
# Event types
class ET:
ENABLE = 'enable'
PRE_ENABLE = 'preEnable'
OVERRIDE_LATERAL = 'overrideLateral'
OVERRIDE_LONGITUDINAL = 'overrideLongitudinal'
NO_ENTRY = 'noEntry'
WARNING = 'warning'
USER_DISABLE = 'userDisable'
SOFT_DISABLE = 'softDisable'
IMMEDIATE_DISABLE = 'immediateDisable'
PERMANENT = 'permanent'
class Alert:
def __init__(self,
alert_text_1: str,
alert_text_2: str,
alert_status: log.SelfdriveState.AlertStatus,
alert_size: log.SelfdriveState.AlertSize,
priority: Priority,
visual_alert: car.CarControl.HUDControl.VisualAlert,
audible_alert: car.CarControl.HUDControl.AudibleAlert,
duration: float,
creation_delay: float = 0.):
self.alert_text_1 = alert_text_1
self.alert_text_2 = alert_text_2
self.alert_status = alert_status
self.alert_size = alert_size
self.priority = priority
self.visual_alert = visual_alert
self.audible_alert = audible_alert
self.duration = int(duration / DT_CTRL)
self.creation_delay = creation_delay
self.alert_type = ""
self.event_type: str | None = None
def __str__(self) -> str:
return f"{self.alert_text_1}/{self.alert_text_2} {self.priority} {self.visual_alert} {self.audible_alert}"
def __gt__(self, alert2) -> bool:
if not isinstance(alert2, Alert):
return False
return self.priority > alert2.priority
class AlertBase(Alert):
def __init__(self, alert_text_1: str, alert_text_2: str, alert_status: log.SelfdriveState.AlertStatus,
alert_size: log.SelfdriveState.AlertSize, priority: Priority,
visual_alert: car.CarControl.HUDControl.VisualAlert,
audible_alert: car.CarControl.HUDControl.AudibleAlert, duration: float):
super().__init__(alert_text_1, alert_text_2, alert_status, alert_size, priority, visual_alert, audible_alert, duration)
AlertCallbackType = Callable[[car.CarParams, car.CarState, messaging.SubMaster, bool, int, log.ControlsState], Alert]
class EventsBase:
def __init__(self):
self.events: list[int] = []
self.static_events: list[int] = []
self.event_counters = {}
@property
def names(self) -> list[int]:
return self.events
def __len__(self) -> int:
return len(self.events)
def add(self, event_name: int, static: bool = False) -> None:
if static:
bisect.insort(self.static_events, event_name)
bisect.insort(self.events, event_name)
def clear(self) -> None:
self.event_counters = {k: (v + 1 if k in self.events else 0) for k, v in self.event_counters.items()}
self.events = self.static_events.copy()
def contains(self, event_type: str) -> bool:
return any(event_type in self.get_events_mapping().get(e, {}) for e in self.events)
def create_alerts(self, event_types: list[str], callback_args=None):
if callback_args is None:
callback_args = []
ret = []
for e in self.events:
types = self.get_events_mapping()[e].keys()
for et in event_types:
if et in types:
alert = self.get_events_mapping()[e][et]
if not isinstance(alert, Alert):
alert = alert(*callback_args)
if DT_CTRL * (self.event_counters[e] + 1) >= alert.creation_delay:
alert.alert_type = f"{self.get_event_name(e)}/{et}"
alert.event_type = et
ret.append(alert)
return ret
def add_from_msg(self, events):
for e in events:
bisect.insort(self.events, e.name.raw)
def to_msg(self):
ret = []
for event_name in self.events:
event = self.get_event_msg_type().new_message()
event.name = event_name
for event_type in self.get_events_mapping().get(event_name, {}):
setattr(event, event_type, True)
ret.append(event)
return ret
def has(self, event_name: int) -> bool:
return event_name in self.events
def contains_in_list(self, events_list: list[int]) -> bool:
return any(event_name in self.events for event_name in events_list)
def remove(self, event_name: int, static: bool = False) -> None:
if static and event_name in self.static_events:
self.static_events.remove(event_name)
if event_name in self.events:
self.event_counters[event_name] = self.event_counters[event_name] + 1
self.events.remove(event_name)
@abstractmethod
def get_events_mapping(self) -> dict[int, dict[str, Alert | AlertCallbackType]]:
raise NotImplementedError
@abstractmethod
def get_event_name(self, event: int) -> str:
raise NotImplementedError
@abstractmethod
def get_event_msg_type(self):
raise NotImplementedError
EmptyAlert = Alert("" , "", AlertStatus.normal, AlertSize.none, Priority.LOWEST,
VisualAlert.none, AudibleAlert.none, 0)
class NoEntryAlert(Alert):
def __init__(self, alert_text_2: str,
alert_text_1: str = "openpilot Unavailable",
visual_alert: car.CarControl.HUDControl.VisualAlert=VisualAlert.none):
super().__init__(alert_text_1, alert_text_2, AlertStatus.normal,
AlertSize.mid, Priority.LOW, visual_alert,
AudibleAlert.refuse, 3.)
class SoftDisableAlert(Alert):
def __init__(self, alert_text_2: str):
super().__init__("TAKE CONTROL IMMEDIATELY", alert_text_2,
AlertStatus.userPrompt, AlertSize.full,
Priority.MID, VisualAlert.steerRequired,
AudibleAlert.warningSoft, 2.),
# less harsh version of SoftDisable, where the condition is user-triggered
class UserSoftDisableAlert(SoftDisableAlert):
def __init__(self, alert_text_2: str):
super().__init__(alert_text_2),
self.alert_text_1 = "openpilot will disengage"
class ImmediateDisableAlert(Alert):
def __init__(self, alert_text_2: str):
super().__init__("TAKE CONTROL IMMEDIATELY", alert_text_2,
AlertStatus.critical, AlertSize.full,
Priority.HIGHEST, VisualAlert.steerRequired,
AudibleAlert.warningImmediate, 4.),
class EngagementAlert(Alert):
def __init__(self, audible_alert: car.CarControl.HUDControl.AudibleAlert):
super().__init__("", "",
AlertStatus.normal, AlertSize.none,
Priority.MID, VisualAlert.none,
audible_alert, .2),
class NormalPermanentAlert(Alert):
def __init__(self, alert_text_1: str, alert_text_2: str = "", duration: float = 0.2, priority: Priority = Priority.LOWER, creation_delay: float = 0.):
super().__init__(alert_text_1, alert_text_2,
AlertStatus.normal, AlertSize.mid if len(alert_text_2) else AlertSize.small,
priority, VisualAlert.none, AudibleAlert.none, duration, creation_delay=creation_delay),
class StartupAlert(Alert):
def __init__(self, alert_text_1: str, alert_text_2: str = "Always keep hands on wheel and eyes on road", alert_status=AlertStatus.normal):
super().__init__(alert_text_1, alert_text_2,
alert_status, AlertSize.mid,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 5.),
+4 -6
View File
@@ -55,7 +55,7 @@ public:
float fl_pix = 0;
CameraState(SpectraMaster *master, const CameraConfig &config) : camera(master, config, true /*config.stream_type == VISION_STREAM_ROAD*/) {};
CameraState(SpectraMaster *master, const CameraConfig &config) : camera(master, config, config.stream_type == VISION_STREAM_ROAD) {};
~CameraState();
void init(VisionIpcServer *v, cl_device_id device_id, cl_context ctx);
void update_exposure_score(float desired_ev, int exp_t, int exp_g_idx, float exp_gain);
@@ -97,7 +97,7 @@ void CameraState::set_exposure_rect() {
};
int h_ref = 1208;
/*
exposure target intrinsics is
exposure target intrinics is
[
[F, 0, 0.5*ae_xywh[2]]
[0, F, 0.5*H-ae_xywh[1]]
@@ -127,8 +127,6 @@ void CameraState::update_exposure_score(float desired_ev, int exp_t, int exp_g_i
void CameraState::set_camera_exposure(float grey_frac) {
if (!camera.enabled) return;
std::vector<double> target_grey_minimums = {0.1, 0.1, 0.125}; // wide, road, driver
const float dt = 0.05;
const float ts_grey = 10.0;
@@ -145,8 +143,8 @@ void CameraState::set_camera_exposure(float grey_frac) {
const auto &sensor = camera.sensor;
const float cur_ev_ = cur_ev[camera.buf.cur_frame_data.frame_id % 3] * sensor->ev_scale;
// Scale target grey between min and 0.4 depending on lighting conditions
float new_target_grey = std::clamp(0.4 - 0.3 * log2(1.0 + sensor->target_grey_factor*cur_ev_) / log2(6000.0), target_grey_minimums[camera.cc.camera_num], 0.4);
// Scale target grey between 0.1 and 0.4 depending on lighting conditions
float new_target_grey = std::clamp(0.4 - 0.3 * log2(1.0 + sensor->target_grey_factor*cur_ev_) / log2(6000.0), 0.1, 0.4);
float target_grey = (1.0 - k_grey) * target_grey_fraction + k_grey * new_target_grey;
float desired_ev = std::clamp(cur_ev_ / sensor->ev_scale * target_grey / grey_frac, sensor->min_ev, sensor->max_ev);
+10 -22
View File
@@ -258,10 +258,6 @@ int SpectraCamera::clear_req_queue() {
req_mgr_flush_request.flush_type = CAM_REQ_MGR_FLUSH_TYPE_ALL;
int ret = do_cam_control(m->video0_fd, CAM_REQ_MGR_FLUSH_REQ, &req_mgr_flush_request, sizeof(req_mgr_flush_request));
// LOGD("flushed all req: %d", ret);
for (int i = 0; i < MAX_IFE_BUFS; ++i) {
destroySyncObjectAt(i);
}
return ret;
}
@@ -693,7 +689,16 @@ void SpectraCamera::enqueue_buffer(int i, bool dp) {
buf.queue(i);
}
destroySyncObjectAt(i);
// destroy old output fence
for (auto so : {sync_objs, sync_objs_bps_out}) {
if (so[i] == 0) continue;
struct cam_sync_info sync_destroy = {0};
sync_destroy.sync_obj = so[i];
ret = do_sync_control(m->cam_sync_fd, CAM_SYNC_DESTROY, &sync_destroy, sizeof(sync_destroy));
if (ret != 0) {
LOGE("failed to destroy sync object: %d %d", ret, sync_destroy.sync_obj);
}
}
}
// create output fences
@@ -731,23 +736,6 @@ void SpectraCamera::enqueue_buffer(int i, bool dp) {
config_bps(i, request_id);
}
void SpectraCamera::destroySyncObjectAt(int index) {
auto destroy_sync_obj = [](int cam_sync_fd, int32_t &sync_obj) {
if (sync_obj == 0) return;
struct cam_sync_info sync_destroy = {.sync_obj = sync_obj};
int ret = do_sync_control(cam_sync_fd, CAM_SYNC_DESTROY, &sync_destroy, sizeof(sync_destroy));
if (ret != 0) {
LOGE("Failed to destroy sync object: %d, sync_obj: %d", ret, sync_destroy.sync_obj);
}
sync_obj = 0; // Reset the sync object to 0
};
destroy_sync_obj(m->cam_sync_fd, sync_objs[index]);
destroy_sync_obj(m->cam_sync_fd, sync_objs_bps_out[index]);
}
void SpectraCamera::camera_map_bufs() {
int ret;
for (int i = 0; i < ife_buf_depth; i++) {
+3 -17
View File
@@ -1,6 +1,5 @@
#pragma once
#include <sys/mman.h>
#include <functional>
#include <memory>
#include <optional>
@@ -73,21 +72,10 @@ public:
class SpectraBuf {
public:
SpectraBuf() = default;
~SpectraBuf() {
if (video_fd >= 0 && ptr) {
munmap(ptr, mmap_size);
release(video_fd, handle);
}
}
void init(SpectraMaster *m, int s, int a, int flags, int mmu_hdl = 0, int mmu_hdl2 = 0, int count=1) {
video_fd = m->video0_fd;
size = s;
alignment = a;
mmap_size = aligned_size() * count;
void *p = alloc_w_mmu_hdl(video_fd, mmap_size, (uint32_t*)&handle, alignment, flags, mmu_hdl, mmu_hdl2);
void *p = alloc_w_mmu_hdl(m->video0_fd, ALIGNED_SIZE(size, alignment)*count, (uint32_t*)&handle, alignment, flags, mmu_hdl, mmu_hdl2);
ptr = (unsigned char*)p;
assert(ptr != NULL);
};
@@ -96,9 +84,8 @@ public:
return ALIGNED_SIZE(size, alignment);
};
int video_fd = -1;
unsigned char *ptr = nullptr;
int size = 0, alignment = 0, handle = 0, mmap_size = 0;
unsigned char *ptr;
int size, alignment, handle;
};
class SpectraCamera {
@@ -127,7 +114,6 @@ public:
void configICP();
void configCSIPHY();
void linkDevices();
void destroySyncObjectAt(int index);
// *** state ***

Some files were not shown because too many files have changed in this diff Show More